package Viewer;

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.Toolkit;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;

import sun.text.normalizer.Replaceable;

import DataModel.Feature;
import DataModel.FeatureBucket;
import DataModel.FeatureHolder;
import DataModel.LociHolder;
import DataModel.Tupel;
import Interfaces.SortableElements;

/**
 * The Drawpanel handles all kinds of visualisation liek wiggle plot features
 * menus etc.. Is also the Controller of mouse and keyboard on panel.
 * 
 * @author Stefan Lorenz<br>
 * <br>
 *         28.11.2012
 */
@SuppressWarnings("serial")
public class DrawPanel extends JPanel implements MouseWheelListener, MouseMotionListener, MouseListener, KeyListener, FocusListener {

	/**
	 * Browsing session frame of GeneScapes
	 */
	private Viewer viewer;
	/**
	 * Defines the point where the mouse button is pressed. Is needed for
	 * drawing the selection frame.
	 */
	private Point posMousePress = new Point();
	/**
	 * Defines the point where the mouse button dragged. Is needed for drawing
	 * the selection frame.
	 */
	private Point posMouseDrag = new Point();

	/**
	 * Shows to which track index the dragged wiggle plot belongs to and for
	 * defining the right menu
	 */
	private int dragWiggle = -1;
	/**
	 * Shows to which track index the dragged features belongs to and for
	 * defining the right menu
	 */
	private int dragTracks = -1;
	/**
	 * Shows to which track index the dragged six frame translation belongs to
	 * and for defining the right menu
	 */
	private int dragSixFrameTranslation = -1;
	/**
	 * Shows to which track index the dragged plus stranded sequence belongs to
	 * and for defining the right menu
	 */
	private int dragDNAPlus = -1;
	/**
	 * Shows to which track index the dragged minus stranded sequence belongs to
	 * and for defining the right menu
	 */
	private int dragDNAMinus = -1;
	/**
	 * Enables/disables the information window
	 */
	private boolean showInformationWindow;
	/**
	 * Enables/disables the selection frame to select featrues or sequences.
	 */
	private boolean showSelectionFrame = true;
	/**
	 * Enables/disables the track settings menu
	 */
	private boolean showSettingsMenu = false;
	/**
	 * Enables/disables the selection of sequences
	 */
	private boolean isSelectSequences;
	/**
	 * Contains values for the wiggle plot.<br>
	 * The length of this array is equal to the width of the {@link Viewer} <br>
	 * and changes if the width changes.
	 */
	private float wigglePlotPoints[];
	/**
	 * Temporary values for painting the wiggle plot x axes
	 */
	private int[] tempx;
	/**
	 * Temporary yvalues for painting the wiggle plot yaxes
	 */
	private int[] tempy;

	/**
	 * The information window where information about features can get received
	 */
	private InformationWindow informationWindow;
	/**
	 * The tooltip shows the value of the wiggle plot on the hovered position
	 */
	private WiggleInfoWindow tooltip;

	/**
	 * This tuple shows the selected menu type.<br>
	 * The start value describes the kind of visualisation:<br>
	 * 1: wiggle plot<br>
	 * 2: six frame translation<br>
	 * 3: plus sequence<br>
	 * -3: minus sequence<br>
	 * The stop value describes the track index
	 */
	private Tupel selectedMenu;
	private Polygon orfPolygon = new Polygon();
	private String md;

	/**
	 * The Constructor of the panel
	 * 
	 * @param viewer
	 */
	public DrawPanel(Viewer viewer) {
		// initialize information widgets
		this.viewer = viewer;
		this.informationWindow = new InformationWindow(this.viewer);
		this.tooltip = new WiggleInfoWindow();
		this.showInformationWindow = false;
		this.setFocusable(true);
		// initialize object needed for the wiggle plot
		this.wigglePlotPoints = new float[this.getWidth()];
		this.tempx = new int[this.wigglePlotPoints.length];
		this.tempy = new int[this.wigglePlotPoints.length];
		// add listeners
		this.addMouseWheelListener(this);
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
		this.addKeyListener(this);
		this.addFocusListener(this);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.JComponent#paint(java.awt.Graphics)
	 */
	public void paint(Graphics g) {
		super.paint(g);
		this.viewer.getSliderPanel().repaint();
		this.viewer.updateMemoryBarValues();
		Graphics2D g2 = (Graphics2D) g;
		g2.setFont(new Font("arial", Font.BOLD, 12));
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
		// changes the length of the wiggle plot array if the width changed
		if (this.wigglePlotPoints.length != this.getWidth()) {
			this.wigglePlotPoints = new float[this.getWidth()];
			this.tempx = new int[this.wigglePlotPoints.length];
			this.tempy = new int[this.wigglePlotPoints.length];
		}

		// paint background color
		g2.setColor(this.viewer.getSettings().getBackgroundColor());
		g2.fillRect(0, 0, (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth(), 4000);

		// paint selected features
		paintSelected(g2);

		// *************************************
		// PAINT TRACKS
		// *************************************
		for (int i = 0; i < this.viewer.getLoadedTracks().length; i++) {
			if (this.viewer.getLoadedTracks()[i] == null)
				continue;

			// ********************************************
			// LOADED FASTA
			// ********************************************
			if (this.viewer.getLoadedTracks()[i].getTypeOfFile().equals("fas")) {

				// SIX FRAME TRANSLATION
				g2.setColor(this.viewer.getSettings().getLabelingColor());
				g2.drawLine(0, this.viewer.getSettings().getSixFrameSettings()[i].getPosition(), 20, this.viewer.getSettings().getSixFrameSettings()[i].getPosition());
				if (this.viewer.getRangeOfBrowser() < 100000 && this.viewer.getSettings().getSixFrameSettings()[i].isSixFrameShown()) {
					paintSixFrame(g2, i);
				}
				// IUPAC SEARCH AND SEQUENCE
				paintIupacMotif(g2, i);
				paintSequence(g2, i);
			}

			// ********************************************
			// LOADED GBK EMBL
			// ********************************************
			if (this.viewer.getLoadedTracks()[i].getTypeOfFile().contains("gbk") || this.viewer.getLoadedTracks()[i].getTypeOfFile().contains("embl")) {
				for (int x = 0; x < wigglePlotPoints.length; x++) {
					this.wigglePlotPoints[x] = 0;
				}
				// SIX FRAME TRANSLATION
				// EXCEPT TRACK 0 (ANNOTATION TRACK)
				if (i != 0) {
					g2.setColor(this.viewer.getSettings().getLabelingColor());
					g2.drawLine(0, this.viewer.getSettings().getSixFrameSettings()[i].getPosition(), 20, this.viewer.getSettings().getSixFrameSettings()[i].getPosition());
					if (i != 0 && this.viewer.getRangeOfBrowser() < 100000 && this.viewer.getSettings().getSixFrameSettings()[i].isSixFrameShown()) {
						paintSixFrame(g2, i);
					}
					// IUPAC SEARCH AND SEQUENCE
					paintIupacMotif(g2, i);
					paintSequence(g2, i);
				}
				// TRACK LINES AND INDICES
				g2.setColor(this.viewer.getSettings().getLabelingColor());
				if (i != 0) {
					g2.drawLine(0, this.viewer.getSettings().getTracksettings()[i].getPosition(), 20, this.viewer.getSettings().getTracksettings()[i].getPosition());
					g2.drawString(String.valueOf(i), 1, this.viewer.getSettings().getTracksettings()[i].getPosition() - 5);
				} else if (i == 0 && this.viewer.getNewAnnotationList().size() > 0) {
					g2.drawLine(0, this.viewer.getSettings().getTracksettings()[i].getPosition(), 20, this.viewer.getSettings().getTracksettings()[i].getPosition());
					g2.drawString("0", 1, this.viewer.getSettings().getTracksettings()[i].getPosition() - 5);
				}
				LociHolder trackGenome = (LociHolder) this.viewer.getLoadedTracks()[i];
				int index = 0;
				if (i != 0)
					index = trackGenome.getFeatureInRange(this.viewer.getSelectedLocus(), this.viewer.getPositionOfBrowser(i), this.viewer.getPositionOfBrowser(i) + this.viewer.getRangeOfBrowser());
				if (index > 20)
					index -= 19;
				if (index == -1)
					index = 0;
				this.viewer.setFirstBucketIndex(index);
				int bucketOverlap = 0;
				int featureOverlap = 0;
				for (int j = index; j < trackGenome.getList().size(); j++) {
					if (trackGenome.getList().get(j).getStart() > this.viewer.getPositionOfBrowser(i) + this.viewer.getRangeOfBrowser())
						break;

					try {
						if ((trackGenome.getList().get(j - 1).getStop() >= trackGenome.getList().get(j).getStart()))
							bucketOverlap += this.viewer.getSettings().getTracksettings()[i].getBucketSpace();
						else if ((trackGenome.getList().get(j - 2).getStop() >= trackGenome.getList().get(j).getStart()))
							bucketOverlap += this.viewer.getSettings().getTracksettings()[i].getBucketSpace();
						else if ((trackGenome.getList().get(j - 3).getStop() >= trackGenome.getList().get(j).getStart()))
							bucketOverlap += this.viewer.getSettings().getTracksettings()[i].getBucketSpace();
						else
							bucketOverlap = 0;

					} catch (Exception e) {
						// Nothing to do here
						// Exception cause of testing orf with index i-1
					}
					featureOverlap = 0;
					FeatureBucket tar = trackGenome.getList().get(j);
					if (i == 0 && trackGenome.getList().size() - 1 == j) {
						paintSelectedDots(tar, g2);
					}
					float factor = (float) this.getWidth() / (float) this.viewer.getRangeOfBrowser();
					int length = (int) ((tar.getStop() - tar.getStart()) * factor);
					if (length > 80
							&& (this.viewer.getSettings().getTracksettings()[i].getFeatureShown(0) || this.viewer.getSettings().getTracksettings()[i].getFeatureShown(1) || this.viewer.getSettings().getTracksettings()[i].getFeatureShown(3) || this.viewer
									.getSettings().getTracksettings()[i].getFeatureShown(2))) {
						int yPos = this.viewer.getSettings().getTracksettings()[i].getPosition() + bucketOverlap;
						int start = (int) ((tar.getStart() - this.viewer.getPositionOfBrowser(i)) * factor);
						g2.setColor(this.viewer.getSettings().getLabelingColor());

						Font f = g2.getFont();
						g2.setFont(new Font("arial", Font.BOLD, this.viewer.getSettings().getTracksettings()[i].getLabelSize()));
						g2.drawString(tar.getName(), start, yPos - 10);
						g2.setFont(f);

					}
					for (int j2 = 0; j2 < tar.getFeaturesOfBucket().size(); j2++) {
						if (tar.getFeaturesOfBucket().get(j2).getType().equals("source"))
							break;
						try {
							if ((tar.getFeaturesOfBucket().get(j2 - 1).getStop() >= tar.getFeaturesOfBucket().get(j2).getStart()))
								featureOverlap += this.viewer.getSettings().getTracksettings()[i].getSpace();
						} catch (Exception e) {
						}
						fillWigglePoints(i, trackGenome.getList().get(j).getFeaturesOfBucket().get(j2));
						paintFeature(trackGenome.getList().get(j).getFeaturesOfBucket().get(j2), true, bucketOverlap + featureOverlap, i, g2);
					}
				}
				if (i != 0 || (i == 0 && this.viewer.getNewAnnotationList().size() > 0))
					paintWigglePlot(g2, i);
			}

			// *************************************
			// GFF & BED & SAM & GTF & BAM
			// *************************************
			else if (this.viewer.getLoadedTracks()[i].getTypeOfFile().equals("gff") || this.viewer.getLoadedTracks()[i].getTypeOfFile().equals("bed") || this.viewer.getLoadedTracks()[i].getTypeOfFile().equals("gtf")
					|| this.viewer.getLoadedTracks()[i].getTypeOfFile().equals("sam")) {
				g2.setColor(this.viewer.getSettings().getLabelingColor());
				g2.drawLine(0, this.viewer.getSettings().getTracksettings()[i].getPosition(), 20, this.viewer.getSettings().getTracksettings()[i].getPosition());
				g2.drawString(String.valueOf(i), 1, this.viewer.getSettings().getTracksettings()[i].getPosition() - 5);
				paintReads(g2, (FeatureHolder) this.viewer.getLoadedTracks()[i], i);
			}
			// *************************************
			// WIG
			// *************************************
			else if (this.viewer.getLoadedTracks()[i].getTypeOfFile().equals("wig")) {
				paintReads(g2, (FeatureHolder) this.viewer.getLoadedTracks()[i], i);
			}
		}

		// ********************
		// Paint Selection Frame
		// ********************
		if (this.showSelectionFrame && this.dragTracks == -1 && this.dragWiggle == -1)
			paintSelectedFrame(g2);

		// ********************
		// paint Positions and infos
		// ********************
		g2.setFont(new Font("arial", Font.BOLD, this.viewer.getSettings().getPositionLabelSize()));
		g2.setColor(this.viewer.getSettings().getLabelingColor());
		g2.drawString(String.valueOf((int) (this.viewer.getPositionOfBrowser(1))), 3, this.viewer.getSettings().getPositionLabelSize());
		g2.drawString(String.valueOf((int) (this.viewer.getPositionOfBrowser(1) + ((float) this.viewer.getRangeOfBrowser() * 0.25) + 1)), (int) (this.getWidth() * 0.25 + 2), this.viewer.getSettings().getPositionLabelSize());
		g2.drawString(String.valueOf((int) (this.viewer.getPositionOfBrowser(1) + ((float) this.viewer.getRangeOfBrowser() / 2) + 1)), this.getWidth() / 2 + 2, this.viewer.getSettings().getPositionLabelSize());
		g2.drawString(String.valueOf((int) (this.viewer.getPositionOfBrowser(1) + ((float) this.viewer.getRangeOfBrowser() * 0.75) + 1)), (int) (this.getWidth() * 0.75 + 2), this.viewer.getSettings().getPositionLabelSize());

		g2.setFont(new Font("arial", Font.BOLD, 10));
		if (this.isSelectSequences)
			g2.drawString("Frame Annotation mode<c>: enabled", 10, this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y + this.viewer.getDrawPanelScrollPane().getViewport().getHeight() - 40);
		else
			g2.drawString("Frame Annotation mode<c>: disabled", 10, this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y + this.viewer.getDrawPanelScrollPane().getViewport().getHeight() - 40);
		if (this.showSelectionFrame)
			g2.drawString("Selection Frame mode<f>: enabled", 10, this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y + this.viewer.getDrawPanelScrollPane().getViewport().getHeight() - 30);
		else
			g2.drawString("Selection Frame mode<f>: disabled", 10, this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y + this.viewer.getDrawPanelScrollPane().getViewport().getHeight() - 30);
		if (this.showInformationWindow)
			g2.drawString("Information Window <t>: enabled", 10, this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y + this.viewer.getDrawPanelScrollPane().getViewport().getHeight() - 20);
		else
			g2.drawString("Information Window <t>: disabled", 10, this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y + this.viewer.getDrawPanelScrollPane().getViewport().getHeight() - 20);
		g2.drawString("#Buckets: " + this.viewer.getNewAnnotationList().size(), 10, this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y + this.viewer.getDrawPanelScrollPane().getViewport().getHeight() - 10);
		g2.setFont(new Font("arial", Font.BOLD, 12));
		// ********************
		// Paint Gray shadow if the draw panel is disabled
		// ********************
		if (!this.viewer.isEnabledViewer()) {
			g2.setColor(Color.BLACK);
			g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
			g2.fillRect(0, 0, this.getWidth(), this.getHeight());
			g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
		}
		// POSITION REQUEST
		if (this.viewer.isFeatureUnpositioned() == -2 && this.viewer.getNewAnnotationList().size() > 0) {
			g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
			g2.setFont(new Font("arial", Font.BOLD, 32));
			g2.setColor(Color.LIGHT_GRAY);
			g2.drawString("SELECT START POSITION...", (int) ((float) this.getWidth() * 0.1) + 1, this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y + this.viewer.getHeight() / 2 + 1);
			g2.setColor(this.viewer.getSettings().getLabelingColor());
			g2.drawString("SELECT START POSITION...", (int) ((float) this.getWidth() * 0.1), this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y + this.viewer.getHeight() / 2);
		} else if (this.viewer.isFeatureUnpositioned() == -1 && this.viewer.getNewAnnotationList().size() > 0) {
			g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
			g2.setFont(new Font("arial", Font.BOLD, 32));
			g2.setColor(Color.LIGHT_GRAY);
			g2.drawString("SELECT STOP POSITION...", (int) ((float) this.getWidth() * 0.1) + 1, this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y + this.viewer.getHeight() / 2 + 1);
			g2.setColor(this.viewer.getSettings().getLabelingColor());
			g2.drawString("SELECT STOP POSITION...", (int) ((float) this.getWidth() * 0.1), this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y + this.viewer.getHeight() / 2);
		}
	}

	/**
	 * Adds points to an polygon to create plus Arrow of Style 2
	 * 
	 * @param yPos
	 *            the y position of the shape
	 * @param height
	 *            the size of the shape
	 * @param start
	 *            the start point of the shape
	 * @param length
	 *            the length of the shape
	 * @param orfPolygon
	 *            the polygon to add points to
	 */
	private void createRectArrowHeadPlus(int yPos, int height, int start, int length, Polygon orfPolygon) {
		orfPolygon.addPoint(start, yPos - (height / 2));
		orfPolygon.addPoint(start + length - 8, yPos - height / 2);
		orfPolygon.addPoint(start + length, yPos);
		orfPolygon.addPoint(start + length - 8, yPos + height / 2);
		orfPolygon.addPoint(start, yPos + (height / 2));
	}

	/**
	 * Adds points to an polygon to create plus Arrow of Style 1
	 * 
	 * @param yPos
	 *            the y position of the shape
	 * @param height
	 *            the size of the shape
	 * @param start
	 *            the start point of the shape
	 * @param length
	 *            the length of the shape
	 * @param orfPolygon
	 *            the polygon to add points to
	 */
	private void createRealArrowHeadPlus(int yPos, int height, int start, int length, Polygon orfPolygon) {
		orfPolygon.addPoint(start, yPos - height / 4);
		orfPolygon.addPoint(start + length - 8, yPos - height / 4);
		orfPolygon.addPoint(start + length - 8, yPos - height / 2);
		orfPolygon.addPoint(start + length, yPos);
		orfPolygon.addPoint(start + length - 8, yPos + height / 2);
		orfPolygon.addPoint(start + length - 8, yPos + height / 4);
		orfPolygon.addPoint(start, yPos + height / 4);
	}

	/**
	 * Adds points to an polygon to create plus Arrow of Style 0
	 * 
	 * @param yPos
	 *            the y position of the shape
	 * @param height
	 *            the size of the shape
	 * @param start
	 *            the start point of the shape
	 * @param length
	 *            the length of the shape
	 * @param orfPolygon
	 *            the polygon to add points to
	 */
	private void createRoundArrowHeadPlus(int yPos, int height, int start, int length, Polygon orfPolygon) {
		orfPolygon.addPoint(start, yPos - (height / 2) + 2);
		orfPolygon.addPoint(start + 1, yPos - (height / 2) + 1);
		orfPolygon.addPoint(start + 3, yPos - (height / 2));
		orfPolygon.addPoint(start + length - 8, yPos - height / 2);
		orfPolygon.addPoint(start + length, yPos);
		orfPolygon.addPoint(start + length - 8, yPos + height / 2);
		orfPolygon.addPoint(start + 3, yPos + (height / 2));
		orfPolygon.addPoint(start + 1, yPos + (height / 2) - 1);
		orfPolygon.addPoint(start, yPos + (height / 2) - 2);
	}

	/**
	 * Adds points to an polygon to create minus Arrow of Style 2
	 * 
	 * @param yPos
	 *            the y position of the shape
	 * @param height
	 *            the size of the shape
	 * @param start
	 *            the start point of the shape
	 * @param length
	 *            the length of the shape
	 * @param orfPolygon
	 *            the polygon to add points to
	 */
	private void createRectArrowHeadMinus(int yPosOfMinus, int height, int start, int length, Polygon orfPolygon) {
		orfPolygon.addPoint(start, yPosOfMinus);
		orfPolygon.addPoint(start + 8, yPosOfMinus - height / 2);
		orfPolygon.addPoint(start + length, yPosOfMinus - height / 2);
		orfPolygon.addPoint(start + length, yPosOfMinus + height / 2);
		orfPolygon.addPoint(start + 8, yPosOfMinus + height / 2);
	}

	/**
	 * Adds points to an polygon to create minus Arrow of Style 1
	 * 
	 * @param yPos
	 *            the y position of the shape
	 * @param height
	 *            the size of the shape
	 * @param start
	 *            the start point of the shape
	 * @param length
	 *            the length of the shape
	 * @param orfPolygon
	 *            the polygon to add points to
	 */
	private void createRealArrowHeadMinus(int yPosOfMinus, int height, int start, int length, Polygon orfPolygon) {
		orfPolygon.addPoint(start, yPosOfMinus);
		orfPolygon.addPoint(start + 8, yPosOfMinus - height / 2);
		orfPolygon.addPoint(start + 8, yPosOfMinus - height / 4);
		orfPolygon.addPoint(start + length, yPosOfMinus - height / 4);
		orfPolygon.addPoint(start + length, yPosOfMinus + height / 4);
		orfPolygon.addPoint(start + 8, yPosOfMinus + height / 4);
		orfPolygon.addPoint(start + 8, yPosOfMinus + height / 2);
	}

	/**
	 * Adds points to an polygon to create minus Arrow of Style 0
	 * 
	 * @param yPos
	 *            the y position of the shape
	 * @param height
	 *            the size of the shape
	 * @param start
	 *            the start point of the shape
	 * @param length
	 *            the length of the shape
	 * @param orfPolygon
	 *            the polygon to add points to
	 */
	private void createRoundArrowHeadMinus(int yPosOfMinus, int height, int start, int length, Polygon orfPolygon) {
		orfPolygon.addPoint(start, yPosOfMinus);
		orfPolygon.addPoint(start + 8, yPosOfMinus - height / 2);
		orfPolygon.addPoint(start + length - 3, yPosOfMinus - height / 2);
		orfPolygon.addPoint(start + length - 1, yPosOfMinus - (height / 2) + 1);
		orfPolygon.addPoint(start + length, yPosOfMinus - (height / 2) + 2);
		orfPolygon.addPoint(start + length, yPosOfMinus + (height / 2) - 2);
		orfPolygon.addPoint(start + length - 1, yPosOfMinus + (height / 2) - 1);
		orfPolygon.addPoint(start + length - 3, yPosOfMinus + height / 2);
		orfPolygon.addPoint(start + length - 3, yPosOfMinus + height / 2);
		orfPolygon.addPoint(start + 8, yPosOfMinus + height / 2);
	}

	/**
	 * Adds points to an polygon to create minus Arrow of Style 0
	 * 
	 * @param yPos
	 *            the y position of the shape
	 * @param height
	 *            the size of the shape
	 * @param start
	 *            the start point of the shape
	 * @param length
	 *            the length of the shape
	 * @param orfPolygon
	 *            the polygon to add points to
	 */
	private void createRectangle(int yPos, int height, int start, int length, Polygon orfPolygon) {
		orfPolygon.addPoint(start, (int) (yPos - ((float) height / 2)));
		orfPolygon.addPoint(start + length, (int) (yPos - ((float) height / 2)));
		orfPolygon.addPoint(start + length, (int) (yPos + (float) height / 2));
		orfPolygon.addPoint(start, (int) (yPos + (float) height / 2));
	}

	/**
	 * Paints a {@link Feature}
	 * 
	 * @param l
	 *            the feature to paint
	 * @param fill
	 *            is it filled ot not
	 * @param yOverlap
	 *            how much space between because of overlapping features
	 * @param trackIndex
	 *            the track index
	 * @param g2
	 *            the graphics to paint with
	 */
	private void paintFeature(Feature l, boolean fill, int yOverlap, int trackIndex, Graphics2D g2) {
		if (l.getType().equals("source"))
			return;

		int yPos = this.viewer.getSettings().getTracksettings()[trackIndex].getPosition() + yOverlap;
		// style defines the form of the feature
		int style = 0;
		int height = 0;
		Color color = Color.RED;

		// set parameter to draw depends on feature type
		if (l.getType().equals("CDS")) {
			if (!this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(2))
				return;
			style = this.viewer.getSettings().getTracksettings()[trackIndex].getLook(2);
			height = this.viewer.getSettings().getTracksettings()[trackIndex].getSize(2);
			color = this.viewer.getSettings().getTracksettings()[trackIndex].getColor(2);
		} else if (l.getType().equals("mRNA")) {
			if (!this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(1))
				return;
			style = this.viewer.getSettings().getTracksettings()[trackIndex].getLook(1);
			height = this.viewer.getSettings().getTracksettings()[trackIndex].getSize(1);
			color = this.viewer.getSettings().getTracksettings()[trackIndex].getColor(1);
		} else if (l.getType().equals("gene")) {
			if (!this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(0))
				return;
			style = this.viewer.getSettings().getTracksettings()[trackIndex].getLook(0);
			height = this.viewer.getSettings().getTracksettings()[trackIndex].getSize(0);
			color = this.viewer.getSettings().getTracksettings()[trackIndex].getColor(0);
		} else {
			if (!this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(3))
				return;
			style = this.viewer.getSettings().getTracksettings()[trackIndex].getLook(3);
			height = this.viewer.getSettings().getTracksettings()[trackIndex].getSize(3);
			color = this.viewer.getSettings().getTracksettings()[trackIndex].getColor(3);
		}

		// calculate position on screen
		float width = this.getWidth();
		float range = this.viewer.getRangeOfBrowser();
		float factor = width / range;
		int start = (int) ((l.getAbsoultePositions().getStart() - this.viewer.getPositionOfBrowser(trackIndex)) * factor);
		int length = (int) ((l.getAbsoultePositions().getStop() - l.getAbsoultePositions().getStart()) * factor);
		g2.setColor(color.darker().darker());

		for (int i = 0; i < l.getListOfPositions().size(); i++) {
			g2.setColor(color);
			orfPolygon.reset();

			start = (int) Math.round(((l.getListOfPositions().get(i).getStart() - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor));
			length = (int) Math.round(((l.getListOfPositions().get(i).getStop() - l.getListOfPositions().get(i).getStart() + 1) * factor));

			if (i < l.getListOfPositions().size() - 1) {
				int stop = (int) Math.round(((l.getListOfPositions().get(i + 1).getStart() - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor));
				int middle = (start + length) + ((stop - (start + length)) / 2);
				g2.drawLine(start + length, yPos, middle, yPos + 5);
				g2.drawLine(middle, yPos + 5, stop, yPos);
			}

			// paint heat features
			if (style == 4) {
				g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.2f));
				g2.setColor(color);
				g2.fillRect(start, yPos - height / 2, length, height);
				g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
			}
			// If the feature is to small only paint normal reactangle
			else if (length < 8) {
				g2.setColor(color);
				g2.fillRect(start, yPos - height / 2, 3, height);
			}
			// Otherwise paint all other forms of a feature
			// Plus Arrow Heads
			else if ((i == l.getListOfPositions().size() - 1 || l.getListOfPositions().size() == 1) && l.getStrand().equals("+")) {

				start = (int) Math.round(((l.getListOfPositions().get(i).getStart() - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor));
				length = (int) Math.round(((l.getListOfPositions().get(i).getStop() - l.getListOfPositions().get(i).getStart() + 1) * factor));

				// style 0 of polygon --
				if (style == 0) {
					createRoundArrowHeadPlus(yPos, height, start, length, orfPolygon);
				}
				// style 1 of polygon ->
				else if (style == 1) {
					createRealArrowHeadPlus(yPos, height, start, length, orfPolygon);
				}
				// style 2 of polygon -- w/o rounded corners
				else if (style == 2) {
					createRectArrowHeadPlus(yPos, height, start, length, orfPolygon);
				} else if (style == 3) {
					createRectangle(yPos, height, start, length, orfPolygon);
				}
				if (fill) {
					g2.setColor(color);
					// TODO:
					g2.fillPolygon(orfPolygon);
					// g2.setColor(color.darker());
					// g2.drawPolygon(orfPolygon);

					// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
					// 0.3f));
					// g2.setColor(Color.GRAY);
					// orfPolygon.translate(4, 4);
					// g2.fillPolygon(orfPolygon);
					// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
					// 1.0f));
					// orfPolygon.translate(-4, -4);
				} else {
					g2.setColor(this.viewer.getSettings().getSelectionColor());
					g2.fillPolygon(orfPolygon);
				}
			}
			// Minus Arrow Head
			else if ((i == 0 || l.getListOfPositions().size() == 1) && l.getStrand().equals("-")) {
				start = (int) ((l.getListOfPositions().get(i).getStart() - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor);
				length = (int) ((l.getListOfPositions().get(i).getStop() + 1 - l.getListOfPositions().get(i).getStart()) * factor);

				if (style == 0) {
					createRoundArrowHeadMinus(yPos, height, start, length, orfPolygon);
				} else if (style == 1) {
					createRealArrowHeadMinus(yPos, height, start, length, orfPolygon);
				} else if (style == 2) {
					createRectArrowHeadMinus(yPos, height, start, length, orfPolygon);
				} else if (style == 3) {
					createRectangle(yPos, height, start, length, orfPolygon);
				}
				if (fill) {
					// TODO:
					g2.setColor(color);
					g2.fillPolygon(orfPolygon);
					// g2.setColor(color.darker());
					// g2.drawPolygon(orfPolygon);
					//
					// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
					// 0.3f));
					// g2.setColor(Color.GRAY);
					// orfPolygon.translate(4, 4);
					// g2.fillPolygon(orfPolygon);
					// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
					// 1.0f));
					// orfPolygon.translate(-4, -4);
				} else {
					g2.setColor(this.viewer.getSettings().getSelectionColor());
					g2.fillPolygon(orfPolygon);
				}
			}

			// No Arrowhead to paint
			else if ((i != l.getListOfPositions().size() - 1 && l.getStrand().equals("+")) || (i != 0 && l.getStrand().equals("-"))) {
				if (style == 0) {
					if (fill) {
						g2.setColor(color);
						g2.fillRoundRect(start, yPos - height / 2, length, height, 8, 8);
						// g2.setColor(color.darker());
						// g2.drawRoundRect(start, yPos - height / 2, length,
						// height, 8, 8);
						//
						// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
						// 0.3f));
						// g2.setColor(Color.GRAY);
						// g2.fillRoundRect(4 + start, 4 + yPos - height / 2,
						// length, height, 8, 8);
						// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
						// 1.0f));
					} else {
						g2.setColor(this.viewer.getSettings().getSelectionColor());
						g2.fillRoundRect(start, yPos - height / 2, length, height, 8, 8);
					}
				} else if (style == 1) {
					if (fill) {
						g2.setPaint(color);
						g2.fillRect(start, yPos - height / 4, length, height / 2 - 1);
						// g2.setColor(color.darker());
						// g2.drawRect(start, yPos - height / 4, length, height
						// / 2 - 1);
						//
						// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
						// 0.3f));
						// g2.setColor(Color.GRAY);
						// g2.fillRect(4 + start, 4 + yPos - height / 4, length,
						// height / 2 - 1);
						// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
						// 1.0f));

					} else {
						g2.setColor(this.viewer.getSettings().getSelectionColor());
						g2.fillRoundRect(start, yPos - height / 4, length, height / 2 - 1, 8, 8);
					}
				} else if (style == 2) {
					if (fill) {
						g2.setPaint(color);
						g2.fillRect(start, yPos - height / 2, length, height);
						// g2.setColor(color.darker());
						// g2.drawRect(start, yPos - height / 2, length,
						// height);
						//
						// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
						// 0.3f));
						// g2.setColor(Color.GRAY);
						// g2.fillRect(4 + start, 4 + yPos - height / 2, length,
						// height);
						// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
						// 1.0f));

					} else {
						g2.setColor(this.viewer.getSettings().getSelectionColor());
						g2.fillRect(start, yPos - height / 2, length, height);
					}
				} else if (style == 3) {
					if (fill) {
						g2.setPaint(color);
						g2.fillRect(start, yPos - height / 2, length, height);
						// g2.setColor(color.darker());
						// g2.drawRect(start, yPos - height / 2, length,
						// height);
						//
						// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
						// 0.3f));
						// g2.setColor(Color.GRAY);
						// g2.fillRect(4 + start, 4 + yPos - height / 2, length,
						// height);
						// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
						// 1.0f));

					} else {
						g2.setColor(this.viewer.getSettings().getSelectionColor());
						g2.fillRect(start, yPos - height / 2, length, height);
					}
				}
			}
			// gbk, ,fasta
			// paint sequence of sam format
			if (l.getType().equals("sam") && this.viewer.getRangeOfBrowser() < 10000) {
				g2.setColor(this.viewer.getSettings().getLabelingColor());
				Font font = g2.getFont();
				g2.setFont(new Font("arial", Font.BOLD, height - 2));

				for (int j = 0; j < l.getAdditionalInformation().size(); j++) {
					// TODO:
					// // paint sequence only if features contain complete
					// sequence
					// -> memory
					// if(l.getAdditionalInformation().get(j).startsWith("/Seq=")){
					// seq =
					// l.getAdditionalInformation().get(j).replace("\"","").replace("/Seq=",
					// "").toUpperCase();
					// for (int j2 = 0; j2 < seq.length(); j2++) {
					// if (seq.charAt(j2) == 'A')
					// g2.setColor(this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(0));
					// else if (seq.charAt(j2) == 'T')
					// g2.setColor(this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(1));
					// else if (seq.charAt(j2) == 'G')
					// g2.setColor(this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(2));
					// else if (seq.charAt(j2) == 'C')
					// g2.setColor(this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(3));
					// else
					// g2.setColor(this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(4));
					// g2.drawString(seq.substring(j2, j2+1), (int)
					// ((l.getStart()-1 + j2 -
					// this.viewer.getPositionOfBrowser(trackIndex)) * factor),
					// (int) (yPos + (0.5 * height)));
					// };
					// }

					// Check MD parsed MD tag which already contains the
					// mismatches base of the read
					// 1A48 -> one match, Read has an A on position two,
					// mismatch because reference has NO A at position two, an
					// 48 matches again
					if (l.getAdditionalInformation().get(j).startsWith("/MD=") && !l.getAdditionalInformation().get(j).startsWith("/MD=\"\"")) {

						md = l.getAdditionalInformation().get(j).replace("\"", "").replace("/MD=", "");
						int posStart = 0;
						int walkedLength = 0;
						// check MD tag splitted in numbers ints and
						// mismatched bases
						for (int k = 0; k < md.split(",").length; k++) {
							
							if (this.viewer.isNumber(md.split(",")[k])) {
								walkedLength = Integer.parseInt(md.split(",")[k]);
							}
							// paint mismatch bases colored
							else {
								walkedLength = 1;
								
								if (md.split(",")[k].equals("A"))
									g2.setColor(this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(0));
								else if (md.split(",")[k].equals("T"))
									g2.setColor(this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(1));
								else if (md.split(",")[k].equals("G"))
									g2.setColor(this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(2));
								else if (md.split(",")[k].equals("C"))
									g2.setColor(this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(3));

								g2.fillRect((int) ((l.getStart() + posStart - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor), yPos - height / 2, 1, height);

								if (this.viewer.getRangeOfBrowser() < 250) {
									g2.setFont(new Font("arial", Font.BOLD, height - 2));
									g2.drawString(md.split(",")[k], (int) ((l.getStart() + posStart - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor) + 1, yPos + (height / 2) - 2);
								}
							}
							posStart += walkedLength;
						}
						break;
					}
				}
				g2.setFont(font);
			}
		}
	}

	/**
	 * Paints the selection frame
	 * 
	 * @param g2
	 *            graphics of the panel
	 */
	private void paintSelectedFrame(Graphics2D g2) {
		int minX = Math.min(posMouseDrag.x, posMousePress.x);
		int maxX = Math.max(posMouseDrag.x, posMousePress.x);

		int minY = Math.min(posMouseDrag.y, posMousePress.y);
		int maxY = Math.max(posMouseDrag.y, posMousePress.y);

		g2.setColor(this.viewer.getSettings().getSelectionColor());
		g2.drawRoundRect(minX, minY, maxX - minX, maxY - minY, 10, 10);

		g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f));
		g2.fillRoundRect(minX, minY, maxX - minX, maxY - minY, 10, 10);
		g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
	}

	/**
	 * Paints iupac nucleotide motif search
	 * 
	 * @param g2
	 *            graphics of the panel
	 */
	private void paintIupacMotif(Graphics2D g2, int trackIndex) {
		// ONLY SHOWN IN A DEFINED RANGE
		if (this.viewer.getShowRestrictionSite() && this.viewer.getRangeOfBrowser() < 400000) {
			float width = this.getWidth();
			float range = this.viewer.getRangeOfBrowser();
			int posInGenom = this.viewer.getPositionOfBrowser(trackIndex);

			try {
				String seq = ((LociHolder) this.viewer.getLoadedTracks()[trackIndex]).getListOfLoci().get(0).getSequence().substring((posInGenom), (int) (posInGenom + range));

				float size = width / seq.length();

				// REGEX IUPAC
				for (int i = 0; i < 3; i++) {
					if (i == 0)
						g2.setColor(this.viewer.getSettings().getMotifColor(0));
					if (i == 1)
						g2.setColor(this.viewer.getSettings().getMotifColor(1));
					if (i == 2)
						g2.setColor(this.viewer.getSettings().getMotifColor(2));

					if (this.viewer.getMotif(i).equals(""))
						continue;
					if (this.viewer.isShowPlusSearch()) {
						Pattern p = Pattern.compile(this.viewer.getRegularExpressionIUPAC(this.viewer.getMotif(i)));
						Matcher matcher = p.matcher(seq);
						while (matcher.find()) {
							if ((int) (matcher.group().length() * size) < 1)
								g2.fillRect((int) (matcher.start() * size), 0, 1, this.getHeight());
							else
								g2.fillRect((int) (matcher.start() * size), 0, (int) (matcher.group().length() * size), this.getHeight());
						}
					}
					if (this.viewer.isShowMinusSearch()) {
						String s = this.viewer.getMotif(i).toUpperCase();
						String comp = "";
						for (int j = s.length() - 1; j >= 0; j--) {
							comp += this.viewer.getComplementOfBase(s.charAt(j));
						}
						Pattern p = Pattern.compile(this.viewer.getRegularExpressionIUPAC(comp));
						Matcher matcher = p.matcher(seq);
						while (matcher.find()) {
							if ((int) (matcher.group().length() * size) < 1)
								g2.fillRect((int) (matcher.start() * size), 0, 1, this.getHeight());
							else
								g2.fillRect((int) (matcher.start() * size), 0, (int) (matcher.group().length() * size), this.getHeight());
						}
					}
				}
			} catch (StringIndexOutOfBoundsException e) {
			}
		}
	}

	/**
	 * Paints track sequence of track index
	 * 
	 * @param g2
	 *            graphics of the panel
	 */
	private void paintSequence(Graphics2D g2, int trackIndex) {
		// RETURN IF NO SEQUENCE
		if (((LociHolder) this.viewer.getLoadedTracks()[trackIndex]).getListOfLoci().get(0).getSequence().length() == 0)
			return;

		Font font = g2.getFont();
		g2.setFont(font);
		g2.setColor(this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideForegroundColor());
		g2.drawString("Seq " + trackIndex + " +", 5, this.viewer.getSettings().getSequenceSettings(trackIndex).getPositionPlusStrand());
		g2.drawString("Seq " + trackIndex + " -", 5, this.viewer.getSettings().getSequenceSettings(trackIndex).getPositionMinusStrand());
		g2.drawLine(0, this.viewer.getSettings().getSequenceSettings(trackIndex).getPositionPlusStrand(), 20, this.viewer.getSettings().getSequenceSettings(trackIndex).getPositionPlusStrand());
		g2.drawLine(0, this.viewer.getSettings().getSequenceSettings(trackIndex).getPositionMinusStrand(), 20, this.viewer.getSettings().getSequenceSettings(trackIndex).getPositionMinusStrand());

		// DNA sequence

		if (this.viewer.getRangeOfBrowser() < 1000 && this.viewer.getSettings().getSequenceSettings(trackIndex).isShown()) {
			// CHECK POSITIONS
			int startSeq = this.viewer.getPositionOfBrowser(trackIndex);
			int stopSeq = this.viewer.getPositionOfBrowser(trackIndex) + this.viewer.getRangeOfBrowser();
			int shift = 0;

			if (startSeq <= 0) {
				startSeq = 0;
				shift = Math.abs(this.viewer.getPositionOfBrowser(trackIndex));
			} else if (stopSeq > this.viewer.getLoadedTracks()[trackIndex].getSize()) {
				shift = this.viewer.getLoadedTracks()[trackIndex].getSize() - stopSeq;
				stopSeq = this.viewer.getLoadedTracks()[trackIndex].getSize();
			}

			if (startSeq >= this.viewer.getLoadedTracks()[trackIndex].getSize())
				return;
			if (stopSeq <= 0)
				return;

			String seq = ((LociHolder) this.viewer.getLoadedTracks()[trackIndex]).getListOfLoci().get(0).getSequence().substring(startSeq, stopSeq).toUpperCase();
			float size = ((float) this.getWidth()) / (seq.length() + Math.abs(shift));

			Color col1 = null;
			Color col2 = null;
			int dnaSize = this.viewer.getSettings().getSequenceSettings(trackIndex).getSize();
			g2.setFont(new Font("arial", Font.BOLD, dnaSize));
			if (shift <= 0)
				shift = 0;

			for (int i = 0; i < seq.length(); i++) {

				if (seq.charAt(i) == 'A' || seq.charAt(i) == 'a') {
					col1 = this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(0);
					col2 = this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(1);
				} else if (seq.charAt(i) == 'T' || seq.charAt(i) == 't') {
					col1 = this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(1);
					col2 = this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(0);
				} else if (seq.charAt(i) == 'C' || seq.charAt(i) == 'c') {
					col1 = this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(3);
					col2 = this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(2);
				} else if (seq.charAt(i) == 'G' || seq.charAt(i) == 'g') {
					col1 = this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(2);
					col2 = this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(3);
				} else {
					col1 = this.viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideBackgroundColor(4);
					col2 = col1;
				}

				g2.setColor(col1);
				g2.fillRect((int) (size * (i + shift)), this.viewer.getSettings().getSequenceSettings(trackIndex).getPositionPlusStrand(), (int) ((size * (i + 1)) - (size * i)), dnaSize);

				g2.setColor(col2);
				g2.fillRect((int) (size * (i + shift)), this.viewer.getSettings().getSequenceSettings(trackIndex).getPositionMinusStrand(), (int) ((size * (i + 1)) - (size * i)), dnaSize);

				if (this.viewer.getRangeOfBrowser() < 200) {
					g2.setColor(viewer.getSettings().getSequenceSettings(trackIndex).getNucleotideForegroundColor());
					g2.drawString(String.valueOf(seq.charAt(i)), (int) (size * (i + shift)), this.viewer.getSettings().getSequenceSettings(trackIndex).getPositionPlusStrand() + dnaSize - 2);
					g2.drawString(String.valueOf(this.viewer.getComplementOfBase(seq.charAt(i))), (int) (size * (i + shift)), this.viewer.getSettings().getSequenceSettings(trackIndex).getPositionMinusStrand() + dnaSize - 2);
				}
			}
		}
		g2.setFont(font);
	}

	/**
	 * Paints six frame translation of track index
	 * 
	 * @param g2
	 *            graphics of the panel
	 */
	private void paintSixFrame(Graphics2D g2, int trackIndex) {
		// RETURN IF NO SEQUENCE
		if (((LociHolder) this.viewer.getLoadedTracks()[trackIndex]).getListOfLoci().get(0).getSequence().length() == 0)
			return;

		g2.setColor(Color.LIGHT_GRAY);
		g2.drawLine(0, this.viewer.getSettings().getSixFrameSettings()[trackIndex].getPosition() + 2, this.getWidth(), this.viewer.getSettings().getSixFrameSettings()[trackIndex].getPosition() + 2);
		g2.drawLine(0, this.viewer.getSettings().getSixFrameSettings()[trackIndex].getPosition() + 7, this.getWidth(), this.viewer.getSettings().getSixFrameSettings()[trackIndex].getPosition() + 7);
		g2.drawLine(0, this.viewer.getSettings().getSixFrameSettings()[trackIndex].getPosition() + 12, this.getWidth(), this.viewer.getSettings().getSixFrameSettings()[trackIndex].getPosition() + 12);
		g2.drawLine(0, this.viewer.getSettings().getSixFrameSettings()[trackIndex].getPosition() + 17, this.getWidth(), this.viewer.getSettings().getSixFrameSettings()[trackIndex].getPosition() + 17);
		g2.drawLine(0, this.viewer.getSettings().getSixFrameSettings()[trackIndex].getPosition() + 22, this.getWidth(), this.viewer.getSettings().getSixFrameSettings()[trackIndex].getPosition() + 22);
		g2.drawLine(0, this.viewer.getSettings().getSixFrameSettings()[trackIndex].getPosition() + 27, this.getWidth(), this.viewer.getSettings().getSixFrameSettings()[trackIndex].getPosition() + 27);

		// CHECK POSITIONS
		int startSeq = this.viewer.getPositionOfBrowser(trackIndex);
		int stopSeq = this.viewer.getPositionOfBrowser(trackIndex) + this.viewer.getRangeOfBrowser();
		int shift = 0;

		if (startSeq <= 0) {
			startSeq = 0;
			shift = Math.abs(this.viewer.getPositionOfBrowser(trackIndex));
		} else if (stopSeq >= this.viewer.getLoadedTracks()[trackIndex].getSize()) {
			shift = this.viewer.getLoadedTracks()[trackIndex].getSize() - stopSeq;
			stopSeq = this.viewer.getLoadedTracks()[trackIndex].getSize();
		}

		if (startSeq >= this.viewer.getLoadedTracks()[trackIndex].getSize())
			return;
		if (stopSeq <= 0)
			return;

		String s = ((LociHolder) this.viewer.getLoadedTracks()[trackIndex]).getListOfLoci().get(0).getSequence().substring(startSeq, stopSeq).toUpperCase();
		float size = ((float) this.getWidth()) / (s.length() + Math.abs(shift));
		Color color = Color.BLACK;

		for (int i = 0; i < this.viewer.getAminoAcidTable().getStartCodons().size(); i++) {
			Pattern p0 = Pattern.compile(this.viewer.getAminoAcidTable().getStartCodons().get(i));
			color = this.viewer.getSettings().getSixFrameSettings()[trackIndex].getStartCodonColor().get(i);
			paintCodon(g2, p0.matcher(s), size, trackIndex, false, color, shift);

			String codonRev = "";
			for (int j = 2; j >= 0; j--) {
				codonRev += this.viewer.getComplementOfBase(this.viewer.getAminoAcidTable().getStartCodons().get(i).charAt(j));
			}
			Pattern p0reverse = Pattern.compile(codonRev);
			color = this.viewer.getSettings().getSixFrameSettings()[trackIndex].getStartCodonColor().get(i + this.viewer.getAminoAcidTable().getStartCodons().size());
			paintCodon(g2, p0reverse.matcher(s), size, trackIndex, true, color, shift);
		}
		for (int i = 0; i < this.viewer.getAminoAcidTable().getStopCodons().size(); i++) {
			Pattern p0 = Pattern.compile(this.viewer.getAminoAcidTable().getStopCodons().get(i));
			color = this.viewer.getSettings().getSixFrameSettings()[trackIndex].getStopCodonColor().get(i);
			paintCodon(g2, p0.matcher(s), size, trackIndex, false, color, shift);

			String codonRev = "";
			for (int j = 2; j >= 0; j--) {
				codonRev += this.viewer.getComplementOfBase(this.viewer.getAminoAcidTable().getStopCodons().get(i).charAt(j));
			}
			Pattern p0reverse = Pattern.compile(codonRev);
			color = this.viewer.getSettings().getSixFrameSettings()[trackIndex].getStopCodonColor().get(i + this.viewer.getAminoAcidTable().getStopCodons().size() - 1);
			paintCodon(g2, p0reverse.matcher(s), size, trackIndex, true, color, shift);
		}
	}

	/**
	 * Paints different Codons of different lanes
	 * 
	 * @param g2
	 *            graphics of the panel
	 * @param matcher
	 *            matcher gives positions of the codons
	 * @param size
	 *            factor calculated of sequence length and width of the panel
	 */
	private void paintCodon(Graphics2D g2, Matcher matcher, float size, int trackIndex, boolean isReverse, Color color, int shift) {
		int yPos = 0;
		if (isReverse)
			yPos = 15;
		Color tmp = g2.getColor();
		g2.setColor(color);
		if (shift < 0)
			shift = 0;
		while (matcher.find()) {
			if ((this.viewer.getPositionOfBrowser(trackIndex) + matcher.start() + shift) % 3 == 0) {
				g2.fillRect((int) (((matcher.start() + shift) * size)), this.viewer.getSettings().getSixFrameSettings()[trackIndex].getPosition() + yPos, 2, 5);
			} else if ((this.viewer.getPositionOfBrowser(trackIndex) + matcher.start() + shift) % 3 == 1) {
				g2.fillRect((int) (((matcher.start() + shift) * size)), this.viewer.getSettings().getSixFrameSettings()[trackIndex].getPosition() + yPos + 5, 2, 5);
			} else if ((this.viewer.getPositionOfBrowser(trackIndex) + matcher.start() + shift) % 3 == 2) {
				g2.fillRect((int) (((matcher.start() + shift) * size)), this.viewer.getSettings().getSixFrameSettings()[trackIndex].getPosition() + yPos + 10, 2, 5);
			}
		}
		g2.setColor(tmp);
	}

	/**
	 * Paints ReadFileFormat features.
	 * 
	 * @param g2
	 *            graphics of the panel
	 * @param readFile
	 *            {@link FeatureHolder} which contains the features
	 * @param trackIndex
	 *            index of the track
	 */
	private void paintReads(Graphics2D g2, FeatureHolder readFile, int trackIndex) {

		for (int x = 0; x < wigglePlotPoints.length; x++) {
			this.wigglePlotPoints[x] = 0;
		}
		int heightPlus = 0;
		int diffHeight = this.viewer.getSettings().getTracksettings()[trackIndex].getBucketSpace() * this.viewer.getSettings().getTracksettings()[trackIndex].getSpace();

		int indexFirstGff = readFile.getFeatureIndexInRange(this.viewer.getPositionOfBrowser(trackIndex), this.viewer.getPositionOfBrowser(trackIndex) + this.viewer.getRangeOfBrowser());

		int highestOverlap = 0;
		int highestStop = -1;
		// paint reads
		for (int j = indexFirstGff; j < readFile.size(); j++) {
			if (readFile.get(j).getStart() > this.viewer.getPositionOfBrowser(trackIndex) + this.viewer.getRangeOfBrowser())
				break;

			Feature read = readFile.get(j);
			if (highestStop <= read.getStart())
				highestStop = read.getStart();
			else {
				highestStop = 0;
			}
			// maybe need some overlap
			if (j > 0) {
				if (highestStop >= read.getStart()) {
					heightPlus += this.viewer.getSettings().getTracksettings()[trackIndex].getSpace();
					if (heightPlus > highestOverlap)
						highestOverlap = heightPlus + this.viewer.getSettings().getTracksettings()[trackIndex].getSpace();
					if (heightPlus >= diffHeight)
						heightPlus = 0;
				} else
					heightPlus = 0;

			}
			if (this.viewer.getSettings().getTracksettings()[trackIndex].isReadWiggleShown()
					&& (readFile.getTypeOfFile().equals("wig") || readFile.getTypeOfFile().equals("gff") || readFile.getTypeOfFile().equals("gtf") || readFile.getTypeOfFile().equals("bed") || readFile.getTypeOfFile().equals("sam"))) {
				fillWigglePoints(trackIndex, read);
			}

			// paint reads
			if (this.viewer.getSettings().getTracksettings()[trackIndex].isTrackShown()
					&& (readFile.getTypeOfFile().equals("gff") || readFile.getTypeOfFile().equals("gtf") || readFile.getTypeOfFile().equals("bed") || readFile.getTypeOfFile().equals("sam"))) {
				paintFeature(read, true, heightPlus, trackIndex, g2);
			}
		}
		paintWigglePlot(g2, trackIndex);
	}

	/**
	 * Fills the array of the wiggle plot with data. Calculates the positions of
	 * the features into screen coordinates<br>
	 * and filles the array.
	 * 
	 * @param trackIndex
	 *            index of the track to paint
	 * @param read
	 *            feature
	 */
	private void fillWigglePoints(int trackIndex, Feature read) {

		for (int k = 0; k < read.getListOfPositions().size(); k++) {
			// calculate Wiggle plot
			if (this.viewer.getSettings().getTracksettings()[trackIndex].isReadWiggleShown() && this.viewer.getRangeOfBrowser() < 2000000) {
				float ntPerPx = (float) this.viewer.getRangeOfBrowser() / this.getWidth();
				int startPos = (read.getListOfPositions().get(k).getStart() - this.viewer.getPositionOfBrowser(trackIndex) - 1);
				int stopPos = (read.getListOfPositions().get(k).getStop() - this.viewer.getPositionOfBrowser(trackIndex) - 1);
				for (int x = 0; x < wigglePlotPoints.length; x++) {
					if (startPos <= (x * ntPerPx) && stopPos >= (x * ntPerPx) - 1) {
						// show normal wiggle plot
						// TODO: either 1 or the real score -> using 1 for bam file otherwise mapping qual is counted						
						if (this.viewer.getLoadedTracks()[trackIndex].getTypeOfFile().equals("bam") | this.viewer.getLoadedTracks()[trackIndex].getTypeOfFile().equals("sam"))
							this.wigglePlotPoints[x] += 1;
						else
							this.wigglePlotPoints[x] += read.getScore();
					}
				}
			}
		}
	}

	/**
	 * Paints selected features
	 * 
	 * @param g2
	 */
	private void paintSelected(Graphics2D g2) {
		Color col = g2.getColor();
		g2.setColor(this.viewer.getSettings().getSelectionColor());
		for (int i = 0; i < this.viewer.getSelectedFeatureList().size(); i++) {
			paintSelectedDots(this.viewer.getSelectedFeatureList().get(i), g2);
		}
		g2.setColor(col);
	}

	/**
	 * Paints Wiggleplot of track with the index
	 * 
	 * @param g2
	 * @param index
	 *            index of the track
	 */
	private void paintWigglePlot(Graphics2D g2, int index) {
		if (this.viewer.getSettings().getTracksettings()[index].isReadWiggleShown() && this.viewer.getRangeOfBrowser() < 2000000) {
			for (int i = 0; i < this.wigglePlotPoints.length; i++) {
				tempx[i] = i;
				if (this.wigglePlotPoints[i] > 1) {
					// Paint wiggle plot upsidedown
					if (this.viewer.getSettings().getTracksettings()[index].isUpsidedownWiggle()) {
						tempy[i] = (int) (this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle() + ((Math.log10(this.wigglePlotPoints[i]) / Math.log10(2)) * this.viewer.getSettings().getTracksettings()[index]
								.getSizeOfReadWiggle())) + 1;
					} else {
						tempy[i] = (int) (this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle() - ((Math.log10(this.wigglePlotPoints[i]) / Math.log10(2)) * this.viewer.getSettings().getTracksettings()[index]
								.getSizeOfReadWiggle())) + 1;
					}
				} else {
					tempy[i] = this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle();
				}
			}
			tempy[0] = this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle();
			tempy[tempy.length - 1] = this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle();

			g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, this.viewer.getSettings().getTracksettings()[index].getTransparencyWiggle()));
			// filled wiggle
			if (this.viewer.getSettings().getTracksettings()[index].isFilledWiggle()) {
				g2.setColor(this.viewer.getSettings().getTracksettings()[index].getColorOfWiggle());
				g2.fillPolygon(tempx, tempy, this.wigglePlotPoints.length);
			}

			g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
			Stroke s = g2.getStroke();
			g2.setStroke(new BasicStroke(this.viewer.getSettings().getTracksettings()[index].getWiggleFrameSize()));
			// dashed
			if (this.viewer.getSettings().getTracksettings()[index].isDashedWiggle()) {
				BasicStroke stroke = new BasicStroke(this.viewer.getSettings().getTracksettings()[index].getWiggleFrameSize(), BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 1, new float[] { 5 }, 5);
				g2.setStroke(stroke);
			}
			// draw wiggel frame
			g2.setColor(this.viewer.getSettings().getTracksettings()[index].getColorOfWiggleFrame());
			g2.drawPolyline(tempx, tempy, this.wigglePlotPoints.length);
			g2.setStroke(s);

			// scale
			g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
			g2.setColor(this.viewer.getSettings().getLabelingColor());
			int ten = (int) ((Math.log10(1024) / Math.log10(2)) * this.viewer.getSettings().getTracksettings()[index].getSizeOfReadWiggle());
			int five = (int) ((Math.log10(32) / Math.log10(2)) * this.viewer.getSettings().getTracksettings()[index].getSizeOfReadWiggle());
			Font f = g2.getFont();
			g2.setFont(new Font("arial", Font.BOLD, this.viewer.getSettings().getTracksettings()[index].getWiggleScaleSize()));

			if (this.viewer.getSettings().getTracksettings()[index].isUpsidedownWiggle()) {
				g2.drawString("10", this.getWidth() - 20 - this.viewer.getSettings().getTracksettings()[index].getWiggleScaleSize(), this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle() + ten);
				g2.drawString("5", this.getWidth() - 15 - this.viewer.getSettings().getTracksettings()[index].getWiggleScaleSize(), this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle() + five);
				g2.drawLine(this.getWidth() - 5, this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle(), this.getWidth() - 5, this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle() + ten);
				g2.drawLine(this.getWidth() - 15, this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle() + ten, this.getWidth() - 5, this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle() + ten);
				g2.drawLine(this.getWidth() - 15, this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle() + five, this.getWidth() - 5, this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle() + five);
			} else {
				g2.drawString("10", this.getWidth() - 20 - this.viewer.getSettings().getTracksettings()[index].getWiggleScaleSize(), this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle() - ten + 11);
				g2.drawString("5", this.getWidth() - 15 - this.viewer.getSettings().getTracksettings()[index].getWiggleScaleSize(), this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle() - five + 11);
				g2.drawLine(this.getWidth() - 5, this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle(), this.getWidth() - 5, this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle() - ten);
				g2.drawLine(this.getWidth() - 15, this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle() - ten, this.getWidth() - 5, this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle() - ten);
				g2.drawLine(this.getWidth() - 15, this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle() - five, this.getWidth() - 5, this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle() - five);
			}
			g2.setFont(f);
		}
		g2.setColor(this.viewer.getSettings().getLabelingColor());
		g2.drawLine(0, this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle(), this.getWidth(), this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle());
		g2.drawString(String.valueOf(index), 1, this.viewer.getSettings().getTracksettings()[index].getPositionOfReadWiggle() - 5);
	}

	/**
	 * Paints selection dot of sortable elements
	 * 
	 * @param l
	 *            a sortable element e.g {@link Feature}
	 * @param g2
	 */
	private void paintSelectedDots(SortableElements l, Graphics2D g2) {
		float width = this.getWidth();
		float range = this.viewer.getRangeOfBrowser();
		float factor = width / range;
		int start = (int) ((l.getStart() - 1 - this.viewer.getPositionOfBrowser(1)) * factor);
		// can be transcriptionalactive region or features
		if (l.getClass() == Feature.class)
			start = (int) ((l.getStart() - 1 - this.viewer.getPositionOfBrowser(((Feature) l).getTrackIndex())) * factor);

		int length = (int) ((l.getStop() - l.getStart() + 1) * factor);
		// g2.fillOval(start, 50, 7, 7);
		Composite normal = g2.getComposite();
		AlphaComposite ac1 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.15f);
		g2.setComposite(ac1);
		g2.fillRect(start, 0, length, this.getHeight());
		g2.setComposite(normal);
	}

	/**
	 * Checks if the mouse cursor hovers over an painted track feature
	 * 
	 * @param e
	 * @param mouseCursorPosition
	 * @return
	 */
	private Feature isInTrack(MouseEvent e, Point mouseCursorPosition) {
		float width = this.getWidth();
		float range = this.viewer.getRangeOfBrowser();
		float factor = width / range;
		int heightPlus = 0;

		for (int trackIndex = 0; trackIndex < this.viewer.getLoadedTracks().length; trackIndex++) {
			if (this.viewer.getLoadedTracks()[trackIndex] == null)
				continue;
			if (!this.viewer.getSettings().getTracksettings()[trackIndex].isTrackShown())
				continue;

			heightPlus = 0;
			int diffHeight = this.viewer.getSettings().getTracksettings()[trackIndex].getBucketSpace() * this.viewer.getSettings().getTracksettings()[trackIndex].getSpace();
			// search in polgon for loaded Gffs, Beds, Sams, Gtfs
			if (this.viewer.getLoadedTracks()[trackIndex].getTypeOfFile().contains("gff") || this.viewer.getLoadedTracks()[trackIndex].getTypeOfFile().contains("bed") || this.viewer.getLoadedTracks()[trackIndex].getTypeOfFile().contains("gtf")
					|| this.viewer.getLoadedTracks()[trackIndex].getTypeOfFile().contains("sam")) {

				FeatureHolder gff = (FeatureHolder) this.viewer.getLoadedTracks()[trackIndex];
				int highestOverlap = 0;
				int index = gff.getFeatureIndexInRange(this.viewer.getPositionOfBrowser(trackIndex), this.viewer.getPositionOfBrowser(trackIndex) + this.viewer.getRangeOfBrowser());
				int style = this.viewer.getSettings().getTracksettings()[trackIndex].getLook(3);
				int height = this.viewer.getSettings().getTracksettings()[trackIndex].getSize(3);
				int highestStop = -1;
				for (int k = index; k < gff.size(); k++) {
					Feature read = gff.get(k);
					if (highestStop <= read.getStart())
						highestStop = read.getStart();
					else {
						highestStop = 0;
					}
					if (read.getStart() > this.viewer.getPositionOfTrack()[trackIndex] + this.viewer.getRangeOfBrowser())
						break;

					// if type of feature is not listed continue to the next
					if (read.getType().equals("gene") && !this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(0) && trackIndex != 0)
						continue;
					else if (read.getType().equals("mRNA") && !this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(1) && trackIndex != 0)
						continue;
					else if (read.getType().equals("CDS") && !this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(2) && trackIndex != 0)
						continue;
					else if (!read.getType().equals("gene") && !read.getType().equals("mRNA") && !read.getType().equals("CDS") && !this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(3) && trackIndex != 0)
						continue;

					// maybe need some overlap
					if (k > 0) {
						if (highestStop >= read.getStart()) {
							heightPlus += this.viewer.getSettings().getTracksettings()[trackIndex].getSpace();
							if (heightPlus > highestOverlap)
								highestOverlap = heightPlus + this.viewer.getSettings().getTracksettings()[trackIndex].getSpace();
							if (heightPlus >= diffHeight)
								heightPlus = 0;
						} else
							heightPlus = 0;
					}
					int yPos = this.viewer.getSettings().getTracksettings()[trackIndex].getPosition() + heightPlus;
					for (int i = 0; i < read.getListOfPositions().size(); i++) {
						Polygon orfPolygon = new Polygon();

						int start = (int) Math.round(((read.getListOfPositions().get(i).getStart() - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor));
						int length = (int) Math.round(((read.getListOfPositions().get(i).getStop() - read.getListOfPositions().get(i).getStart() + 1) * factor));
						// Plus Arrow Heads
						if ((i == read.getListOfPositions().size() - 1 || read.getListOfPositions().size() == 1) && read.getStrand().equals("+")) {

							start = (int) Math.round(((read.getListOfPositions().get(i).getStart() - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor));
							length = (int) Math.round(((read.getListOfPositions().get(i).getStop() - read.getListOfPositions().get(i).getStart() + 1) * factor));
							// style 0 of polygon --
							if (style == 0) {
								createRoundArrowHeadPlus(yPos, height, start, length, orfPolygon);
							}
							// style 1 of polygon ->
							else if (style == 1) {
								createRealArrowHeadPlus(yPos, height, start, length, orfPolygon);
							}
							// style 2 of polygon -- w/o rounded corners
							else if (style == 2) {
								createRectArrowHeadPlus(yPos, height, start, length, orfPolygon);
							} else if (style == 3) {
								createRectangle(yPos, height, start, length, orfPolygon);
							}
						}
						// Minus Arrow Head
						else if ((i == 0 || read.getListOfPositions().size() == 1) && read.getStrand().equals("-")) {
							start = (int) ((read.getListOfPositions().get(i).getStart() - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor);
							length = (int) ((read.getListOfPositions().get(i).getStop() + 1 - read.getListOfPositions().get(i).getStart()) * factor);

							if (style == 0) {
								createRoundArrowHeadMinus(yPos, height, start, length, orfPolygon);
							} else if (style == 1) {
								createRealArrowHeadMinus(yPos, height, start, length, orfPolygon);
							} else if (style == 2) {
								createRectArrowHeadMinus(yPos, height, start, length, orfPolygon);
							} else if (style == 3) {
								createRectangle(yPos, height, start, length, orfPolygon);
							}
						}
						// No Arrowhead to paint
						else if ((i != read.getListOfPositions().size() - 1 && read.getStrand().equals("+")) || (i != 0 && read.getStrand().equals("-"))) {
							if (style == 0 || style == 2) {
								orfPolygon.addPoint(start, yPos - height / 2);
								orfPolygon.addPoint(start + length, yPos - height / 2);
								orfPolygon.addPoint(start + length, yPos + height / 2);
								orfPolygon.addPoint(start, yPos + height / 2);
							} else if (style == 1) {
								orfPolygon.addPoint(start, yPos - height / 4);
								orfPolygon.addPoint(start + length, yPos - height / 4);
								orfPolygon.addPoint(start + length, yPos + height / 4);
								orfPolygon.addPoint(start, yPos + height / 4);
							} else if (style == 3) {
								createRectangle(yPos, height, start, length, orfPolygon);
							}
						}
						if (orfPolygon.contains(mouseCursorPosition)) {
							if (this.showInformationWindow) {
								showInformationWindow(e, read, i, this.viewer.getLoadedTracks()[1].getFile().getName());
							}
							return read;
						}
					}
				}
			}
			// search in polygon for loaded Genomes ( gbk or embl)
			else if (this.viewer.getLoadedTracks()[trackIndex].getTypeOfFile().contains("gbk") || this.viewer.getLoadedTracks()[trackIndex].getTypeOfFile().contains("embl")) {
				LociHolder trackGenome = (LociHolder) this.viewer.getLoadedTracks()[trackIndex];
				int index = 0;
				// all track except track 0 which is your annotation
				if (trackIndex > 0)
					index = trackGenome.getFeatureInRange(this.viewer.getSelectedLocus(), this.viewer.getPositionOfBrowser(trackIndex), this.viewer.getPositionOfBrowser(trackIndex) + this.viewer.getRangeOfBrowser());
				if (index > 20)
					index -= 19;
				if (index == -1)
					index = 0;

				int bucketOverlap = 0;
				int featureOverlap = 0;
				for (int j = index; j < trackGenome.getList().size(); j++) {
					if (trackGenome.getList().get(j).getStart() > this.viewer.getPositionOfBrowser(trackIndex) + this.viewer.getRangeOfBrowser())
						break;

					try {
						if ((trackGenome.getList().get(j - 1).getStop() >= trackGenome.getList().get(j).getStart()))
							bucketOverlap += this.viewer.getSettings().getTracksettings()[trackIndex].getBucketSpace();
						else if ((trackGenome.getList().get(j - 2).getStop() >= trackGenome.getList().get(j).getStart()))
							bucketOverlap += this.viewer.getSettings().getTracksettings()[trackIndex].getBucketSpace();
						else if ((trackGenome.getList().get(j - 3).getStop() >= trackGenome.getList().get(j).getStart()))
							bucketOverlap += this.viewer.getSettings().getTracksettings()[trackIndex].getBucketSpace();
						else
							bucketOverlap = 0;
					} catch (Exception e2) {
					}

					featureOverlap = 0;
					FeatureBucket tar = trackGenome.getList().get(j);
					for (int j2 = 0; j2 < tar.getFeaturesOfBucket().size(); j2++) {
						try {
							if ((tar.getFeaturesOfBucket().get(j2 - 1).getStop() >= tar.getFeaturesOfBucket().get(j2).getStart()))
								featureOverlap += this.viewer.getSettings().getTracksettings()[trackIndex].getSpace();
						} catch (Exception e1) {
						}
						int yOverlap = bucketOverlap + featureOverlap;
						Feature l = tar.getFeaturesOfBucket().get(j2);

						int yPos = this.viewer.getSettings().getTracksettings()[trackIndex].getPosition() + yOverlap;
						int style = 0;
						int height = 0;

						// getYpos of diffrent types
						if (l.getType().equals("CDS")) {
							if (!this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(2))
								continue;
							style = this.viewer.getSettings().getTracksettings()[trackIndex].getLook(2);
							height = this.viewer.getSettings().getTracksettings()[trackIndex].getSize(2);
						} else if (l.getType().equals("mRNA")) {
							if (!this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(1))
								continue;
							style = this.viewer.getSettings().getTracksettings()[trackIndex].getLook(1);
							height = this.viewer.getSettings().getTracksettings()[trackIndex].getSize(1);
						} else if (l.getType().equals("gene")) {
							if (!this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(0))
								continue;
							style = this.viewer.getSettings().getTracksettings()[trackIndex].getLook(0);
							height = this.viewer.getSettings().getTracksettings()[trackIndex].getSize(0);
						} else {
							if (!this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(3))
								continue;
							style = this.viewer.getSettings().getTracksettings()[trackIndex].getLook(3);
							height = this.viewer.getSettings().getTracksettings()[trackIndex].getSize(3);
						}
						int start = (int) ((l.getAbsoultePositions().getStart() - this.viewer.getPositionOfBrowser(trackIndex)) * factor);
						int length = (int) ((l.getAbsoultePositions().getStop() - l.getAbsoultePositions().getStart()) * factor);

						for (int i = 0; i < l.getListOfPositions().size(); i++) {
							Polygon orfPolygon = new Polygon();

							start = (int) Math.round(((l.getListOfPositions().get(i).getStart() - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor));
							length = (int) Math.round(((l.getListOfPositions().get(i).getStop() - l.getListOfPositions().get(i).getStart() + 1) * factor));

							// Plus Arrow Heads
							if ((i == l.getListOfPositions().size() - 1 || l.getListOfPositions().size() == 1) && l.getStrand().equals("+")) {

								start = (int) Math.round(((l.getListOfPositions().get(i).getStart() - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor));
								length = (int) Math.round(((l.getListOfPositions().get(i).getStop() - l.getListOfPositions().get(i).getStart() + 1) * factor));

								// style 0 of polygon --
								if (style == 0) {
									createRoundArrowHeadPlus(yPos, height, start, length, orfPolygon);
								}
								// style 1 of polygon ->
								else if (style == 1) {
									createRealArrowHeadPlus(yPos, height, start, length, orfPolygon);
								}
								// style 2 of polygon -- w/o rounded corners
								else if (style == 2) {
									createRectArrowHeadPlus(yPos, height, start, length, orfPolygon);
								}
								// style 3 of polygon -- w/o rounded corners
								else if (style == 3) {
									createRectangle(yPos, height, start, length, orfPolygon);
								}
							}
							// Minus Arrow Head
							else if ((i == 0 || l.getListOfPositions().size() == 1) && l.getStrand().equals("-")) {
								start = (int) ((l.getListOfPositions().get(i).getStart() - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor);
								length = (int) ((l.getListOfPositions().get(i).getStop() + 1 - l.getListOfPositions().get(i).getStart()) * factor);

								if (style == 0) {
									createRoundArrowHeadMinus(yPos, height, start, length, orfPolygon);
								} else if (style == 1) {
									createRealArrowHeadMinus(yPos, height, start, length, orfPolygon);
								} else if (style == 2) {
									createRectArrowHeadMinus(yPos, height, start, length, orfPolygon);
								} else if (style == 3) {
									createRectangle(yPos, height, start, length, orfPolygon);
								}
							}
							// No Arrowhead to paint
							else if ((i != l.getListOfPositions().size() - 1 && l.getStrand().equals("+")) || (i != 0 && l.getStrand().equals("-"))) {
								if (style == 0 || style == 2) {
									orfPolygon.addPoint(start, yPos - height / 2);
									orfPolygon.addPoint(start + length, yPos - height / 2);
									orfPolygon.addPoint(start + length, yPos + height / 2);
									orfPolygon.addPoint(start, yPos + height / 2);
								} else if (style == 1) {
									orfPolygon.addPoint(start, yPos - height / 4);
									orfPolygon.addPoint(start + length, yPos - height / 4);
									orfPolygon.addPoint(start + length, yPos + height / 4);
									orfPolygon.addPoint(start, yPos + height / 4);
								} else if (style == 3) {
									createRectangle(yPos, height, start, length, orfPolygon);
								}
							}
							if (orfPolygon.contains(mouseCursorPosition)) {
								if (this.showInformationWindow) {
									showInformationWindow(e, l, i, this.viewer.getLoadedTracks()[trackIndex].getFile().getName());
								}
								return l;
							}
						}
					}
				}
			}
		}
		return null;
	}

	/**
	 * Checks if the mouse cursour hover over the wiggle plot
	 * 
	 * @param e
	 * @param point
	 * @return
	 */
	private int isInWiggle(MouseEvent e, Point point) {
		for (int i = 1; i < this.viewer.getLoadedTracks().length; i++) {
			// if no data in track i is loaded
			if (this.viewer.getLoadedTracks()[i] == null)
				continue;
			// reset plot points to 0
			for (int x = 0; x < wigglePlotPoints.length; x++) {
				this.wigglePlotPoints[x] = 0;
			}

			// calc wiggle plot points of gff or bed file
			if (this.viewer.getLoadedTracks()[i].getTypeOfFile().contains("sam") || this.viewer.getLoadedTracks()[i].getTypeOfFile().contains("bed") || this.viewer.getLoadedTracks()[i].getTypeOfFile().contains("gff")
					|| this.viewer.getLoadedTracks()[i].getTypeOfFile().contains("gtf") || this.viewer.getLoadedTracks()[i].getTypeOfFile().contains("wig")) {

				FeatureHolder rf = (FeatureHolder) this.viewer.getLoadedTracks()[i];
				int indexFirstGff = rf.getFeatureIndexInRange(this.viewer.getPositionOfBrowser(i), this.viewer.getPositionOfBrowser(i) + this.viewer.getRangeOfBrowser());
				for (int j = indexFirstGff; j < rf.size(); j++) {
					if (rf.get(j).getStop() > this.viewer.getPositionOfBrowser(i) + this.viewer.getRangeOfBrowser())
						break;
					for (int k = 0; k < rf.get(j).getListOfPositions().size(); k++) {
						// calculate Wiggle plot
						if (this.viewer.getSettings().getTracksettings()[i].isReadWiggleShown() && this.viewer.getRangeOfBrowser() < 150000) {
							float ntPerPx = (float) this.viewer.getRangeOfBrowser() / this.getWidth();
							float startPos = (rf.get(j).getListOfPositions().get(k).getStart() - this.viewer.getPositionOfBrowser(i) - 1);
							float stopPos = (rf.get(j).getListOfPositions().get(k).getStop() - this.viewer.getPositionOfBrowser(i) - 1);

							for (int x = 0; x < wigglePlotPoints.length; x++) {
								if (startPos <= (x * ntPerPx) && stopPos >= (x * ntPerPx)) {
									//TODO:
									if (this.viewer.getLoadedTracks()[i].getTypeOfFile().equals("bam") | this.viewer.getLoadedTracks()[i].getTypeOfFile().equals("sam"))
										this.wigglePlotPoints[x] += 1;
									else
										this.wigglePlotPoints[x] += rf.get(j).getScore();
								}
							}
						}
					}
				}
				try {
					int y;
					if (!this.viewer.getSettings().getTracksettings()[i].isUpsidedownWiggle())
						y = (int) (this.viewer.getSettings().getTracksettings()[i].getPositionOfReadWiggle() - ((Math.log10(this.wigglePlotPoints[(int) point.getX()]) / Math.log10(2)) * this.viewer.getSettings().getTracksettings()[i]
								.getSizeOfReadWiggle())) + 1;
					else
						y = (int) (this.viewer.getSettings().getTracksettings()[i].getPositionOfReadWiggle() + ((Math.log10(this.wigglePlotPoints[(int) point.getX()]) / Math.log10(2)) * this.viewer.getSettings().getTracksettings()[i]
								.getSizeOfReadWiggle())) + 1;

					if (point.getY() <= y + 3 && point.getY() >= y - 3) {
						this.tooltip.setText("Score: " + this.wigglePlotPoints[(int) point.getX()]);
						return i;
					}
				} catch (ArrayIndexOutOfBoundsException e12) {
				}
			}
		}
		return -1;
	}

	/**
	 * Shows the information window with information of covered feature
	 * 
	 * @param e
	 *            mouse event
	 * @param l
	 *            feature to show in information window
	 * @param indexExon
	 *            index of the hovered exon
	 * @param fileName
	 *            filename of data
	 */
	private void showInformationWindow(final MouseEvent e, final Feature l, int indexExon, final String fileName) {
		informationWindow.setDescribedFeatures(l, indexExon, fileName);
		informationWindow.setAlwaysOnTop(true);
		informationWindow.toFront();
		if (!this.viewer.getSettings().isInfoWindowLocationFixed())
			informationWindow.setLocation(e.getLocationOnScreen());
		if (e.isControlDown())
			return;
		if (!this.informationWindow.isVisible()) {
			this.informationWindow.setVisible(true);
		}
	}

	private void setPositionOfFeaturesByFrame(Rectangle rec) {
		for (int i = 1; i < this.viewer.getLoadedTracks().length; i++) {
			if (this.viewer.getLoadedTracks()[i] == null)
				continue;
			if ((viewer.getSettings().getTracksettings()[i].getPosition() >= rec.getY() && viewer.getSettings().getTracksettings()[i].getPosition() <= rec.getY() + rec.getHeight())
					|| (viewer.getSettings().getTracksettings()[i].getPositionOfReadWiggle() >= rec.getY() && viewer.getSettings().getTracksettings()[i].getPositionOfReadWiggle() <= rec.getY() + rec.getHeight())) {

				float width = this.getWidth();

				int posStart = (int) (Math.round(this.viewer.getPositionOfBrowser(i) + ((rec.getX() / width) * this.viewer.getRangeOfBrowser())) + 1);
				int posStop = (int) (Math.round(this.viewer.getPositionOfBrowser(i) + (((rec.getX() + rec.getWidth()) / width) * this.viewer.getRangeOfBrowser())) + 1);
				// if of new created tupel is (1,1) if no position is set
				if (this.viewer.getCurrentCreatedFeature() == null)
					JOptionPane.showMessageDialog(viewer, "Create feature first", "INFORMATION!", JOptionPane.INFORMATION_MESSAGE);
				else {
					if (this.viewer.getCurrentCreatedFeature().getAbsoultePositions().getStart() == 1 && this.viewer.getCurrentCreatedFeature().getAbsoultePositions().getStop() == 1)
						this.viewer.getCurrentCreatedFeature().setAbsoultePositions(new Tupel(posStart, posStop));
					if (posStart < this.viewer.getCurrentCreatedFeature().getAbsoultePositions().getStart())
						this.viewer.getCurrentCreatedFeature().getAbsoultePositions().setStart(posStart);
					if (posStop > this.viewer.getCurrentCreatedFeature().getAbsoultePositions().getStop())
						this.viewer.getCurrentCreatedFeature().getAbsoultePositions().setStop(posStop);

					this.viewer.getCurrentCreatedFeature().getListOfPositions().add(new Tupel(posStart, posStop));

					viewer.setFeatureUnpositioned(0);
				}
			}
		}
	}

	/**
	 * Returns the list of {@link Feature}s which are selected by selection
	 * frame
	 * 
	 * @param rec
	 *            The rectangle represents the selection frame
	 * @return a list with all selected features
	 */
	private ArrayList<Feature> isInSelectionFrame(Rectangle rec) {
		ArrayList<Feature> temp = new ArrayList<Feature>();
		float width = this.getWidth();
		float range = this.viewer.getRangeOfBrowser();
		float factor = width / range;
		int heightPlus = 0;

		for (int trackIndex = 0; trackIndex < this.viewer.getLoadedTracks().length; trackIndex++) {
			if (this.viewer.getLoadedTracks()[trackIndex] == null)
				continue;
			int diffHeight = this.viewer.getSettings().getTracksettings()[trackIndex].getBucketSpace() * this.viewer.getSettings().getTracksettings()[trackIndex].getSpace();
			// ***********************************************
			// search in polgon for loaded Gffs and Beds
			// ***********************************************
			if (this.viewer.getLoadedTracks()[trackIndex].getTypeOfFile().contains("gff") || this.viewer.getLoadedTracks()[trackIndex].getTypeOfFile().contains("bed") || this.viewer.getLoadedTracks()[trackIndex].getTypeOfFile().contains("gtf")
					|| this.viewer.getLoadedTracks()[trackIndex].getTypeOfFile().contains("sam")) {

				if (!this.viewer.getSettings().getTracksettings()[trackIndex].isTrackShown() && trackIndex != 0)
					continue;

				FeatureHolder gff = (FeatureHolder) this.viewer.getLoadedTracks()[trackIndex];
				int highestOverlap = 0;
				int index = gff.getFeatureIndexInRange(this.viewer.getPositionOfBrowser(trackIndex), this.viewer.getPositionOfBrowser(trackIndex) + this.viewer.getRangeOfBrowser());
				int style = this.viewer.getSettings().getTracksettings()[trackIndex].getLook(3);
				int height = this.viewer.getSettings().getTracksettings()[trackIndex].getSize(3);
				int highestStop = -1;

				for (int k = index; k < gff.size(); k++) {
					Feature read = gff.get(k);
					if (highestStop <= read.getStart())
						highestStop = read.getStart();
					else {
						highestStop = -1;
					}

					// if type of feature is not listed continue to the next
					if (read.getType().equals("gene") && !this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(0) && trackIndex != 0)
						continue;
					else if (read.getType().equals("mRNA") && !this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(1) && trackIndex != 0)
						continue;
					else if (read.getType().equals("CDS") && !this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(2) && trackIndex != 0)
						continue;
					else if (!read.getType().equals("gene") && !read.getType().equals("mRNA") && !read.getType().equals("CDS") && !this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(3) && trackIndex != 0)
						continue;

					// maybe need some overlap
					if (k > 0) {
						if (highestStop >= read.getStart()) {
							heightPlus += this.viewer.getSettings().getTracksettings()[trackIndex].getSpace();
							if (heightPlus > highestOverlap)
								highestOverlap = heightPlus + this.viewer.getSettings().getTracksettings()[trackIndex].getSpace();
							if (heightPlus >= diffHeight)
								heightPlus = 0;
						} else
							heightPlus = 0;
					}
					int yPos = this.viewer.getSettings().getTracksettings()[trackIndex].getPosition() + heightPlus;
					for (int i = 0; i < read.getListOfPositions().size(); i++) {
						Polygon orfPolygon = new Polygon();

						int start = (int) Math.round(((read.getListOfPositions().get(i).getStart() - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor));
						int length = (int) Math.round(((read.getListOfPositions().get(i).getStop() - read.getListOfPositions().get(i).getStart() + 1) * factor));

						// Plus Arrow Heads
						if ((i == read.getListOfPositions().size() - 1 || read.getListOfPositions().size() == 1) && read.getStrand().equals("+")) {

							start = (int) Math.round(((read.getListOfPositions().get(i).getStart() - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor));
							length = (int) Math.round(((read.getListOfPositions().get(i).getStop() - read.getListOfPositions().get(i).getStart() + 1) * factor));

							// style 0 of polygon --
							if (style == 0) {
								createRoundArrowHeadPlus(yPos, height, start, length, orfPolygon);
							}
							// style 1 of polygon ->
							else if (style == 1) {
								createRealArrowHeadPlus(yPos, height, start, length, orfPolygon);
							}
							// style 2 of polygon -- w/o rounded corners
							else if (style == 2) {
								createRectArrowHeadPlus(yPos, height, start, length, orfPolygon);
							} else if (style == 3) {
								createRectangle(yPos, height, start, length, orfPolygon);
							}
						}
						// Minus Arrow Head
						else if ((i == 0 || read.getListOfPositions().size() == 1) && read.getStrand().equals("-")) {
							start = (int) ((read.getListOfPositions().get(i).getStart() - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor);
							length = (int) ((read.getListOfPositions().get(i).getStop() + 1 - read.getListOfPositions().get(i).getStart()) * factor);

							if (style == 0) {
								createRoundArrowHeadMinus(yPos, height, start, length, orfPolygon);
							} else if (style == 1) {
								createRealArrowHeadMinus(yPos, height, start, length, orfPolygon);
							} else if (style == 2) {
								createRectArrowHeadMinus(yPos, height, start, length, orfPolygon);
							} else if (style == 3) {
								createRectangle(yPos, height, start, length, orfPolygon);
							}
						}
						// No Arrowhead to paint
						else if ((i != read.getListOfPositions().size() - 1 && read.getStrand().equals("+")) || (i != 0 && read.getStrand().equals("-"))) {
							if (style == 0 || style == 2) {
								orfPolygon.addPoint(start, yPos - height / 2);
								orfPolygon.addPoint(start + length, yPos - height / 2);
								orfPolygon.addPoint(start + length, yPos + height / 2);
								orfPolygon.addPoint(start, yPos + height / 2);
							} else if (style == 1) {
								orfPolygon.addPoint(start, yPos - height / 4);
								orfPolygon.addPoint(start + length, yPos - height / 4);
								orfPolygon.addPoint(start + length, yPos + height / 4);
								orfPolygon.addPoint(start, yPos + height / 4);
							} else if (style == 3) {
								createRectangle(yPos, height, start, length, orfPolygon);
							}
						}
						if (rec.contains(orfPolygon.getBounds())) {
							temp.add(read);
							break;
						}
					}
				}
			}
			// search in polygon for loaded Genomes
			else if (this.viewer.getLoadedTracks()[trackIndex].getTypeOfFile().contains("gbk") || this.viewer.getLoadedTracks()[trackIndex].getTypeOfFile().contains("embl")) {
				LociHolder trackGenome = (LociHolder) this.viewer.getLoadedTracks()[trackIndex];
				int index = 0;
				// all track except track 0 which is your annotation
				if (trackIndex > 0)
					index = trackGenome.getFeatureInRange(this.viewer.getSelectedLocus(), this.viewer.getPositionOfBrowser(trackIndex), this.viewer.getPositionOfBrowser(trackIndex) + this.viewer.getRangeOfBrowser());
				if (index > 20)
					index -= 19;
				if (index == -1)
					index = 0;

				int bucketOverlap = 0;
				int featureOverlap = 0;
				for (int j = index; j < trackGenome.getList().size(); j++) {
					if (trackGenome.getList().get(j).getStart() > this.viewer.getPositionOfBrowser(trackIndex) + this.viewer.getRangeOfBrowser())
						break;

					try {
						if ((trackGenome.getList().get(j - 1).getStop() >= trackGenome.getList().get(j).getStart()))
							bucketOverlap += this.viewer.getSettings().getTracksettings()[trackIndex].getBucketSpace();
						else
							bucketOverlap = 0;
					} catch (Exception e2) {
					}

					featureOverlap = 0;
					FeatureBucket tar = trackGenome.getList().get(j);
					for (int j2 = 0; j2 < tar.getFeaturesOfBucket().size(); j2++) {
						try {
							if ((tar.getFeaturesOfBucket().get(j2 - 1).getStop() >= tar.getFeaturesOfBucket().get(j2).getStart()))
								featureOverlap += this.viewer.getSettings().getTracksettings()[trackIndex].getSpace();
						} catch (Exception e1) {
						}
						int yOverlap = bucketOverlap + featureOverlap;
						Feature l = tar.getFeaturesOfBucket().get(j2);

						int yPos = this.viewer.getSettings().getTracksettings()[trackIndex].getPosition() + yOverlap;
						int style = 0;
						int height = 0;

						// getYpos of diffrent types
						if (l.getType().equals("CDS")) {
							if (!this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(2))
								continue;
							style = this.viewer.getSettings().getTracksettings()[trackIndex].getLook(2);
							height = this.viewer.getSettings().getTracksettings()[trackIndex].getSize(2);
						} else if (l.getType().equals("mRNA")) {
							if (!this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(1))
								continue;
							style = this.viewer.getSettings().getTracksettings()[trackIndex].getLook(1);
							height = this.viewer.getSettings().getTracksettings()[trackIndex].getSize(1);
						} else if (l.getType().equals("gene")) {
							if (!this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(0))
								continue;
							style = this.viewer.getSettings().getTracksettings()[trackIndex].getLook(0);
							height = this.viewer.getSettings().getTracksettings()[trackIndex].getSize(0);
						} else {
							if (!this.viewer.getSettings().getTracksettings()[trackIndex].getFeatureShown(3))
								continue;
							style = this.viewer.getSettings().getTracksettings()[trackIndex].getLook(3);
							height = this.viewer.getSettings().getTracksettings()[trackIndex].getSize(3);
						}
						int start = (int) ((l.getAbsoultePositions().getStart() - this.viewer.getPositionOfBrowser(trackIndex)) * factor);
						int length = (int) ((l.getAbsoultePositions().getStop() - l.getAbsoultePositions().getStart()) * factor);

						for (int i = 0; i < l.getListOfPositions().size(); i++) {
							Polygon orfPolygon = new Polygon();

							start = (int) Math.round(((l.getListOfPositions().get(i).getStart() - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor));
							length = (int) Math.round(((l.getListOfPositions().get(i).getStop() - l.getListOfPositions().get(i).getStart() + 1) * factor));

							// Plus Arrow Heads
							if ((i == l.getListOfPositions().size() - 1 || l.getListOfPositions().size() == 1) && l.getStrand().equals("+")) {

								start = (int) Math.round(((l.getListOfPositions().get(i).getStart() - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor));
								length = (int) Math.round(((l.getListOfPositions().get(i).getStop() - l.getListOfPositions().get(i).getStart() + 1) * factor));

								// style 0 of polygon --
								if (style == 0) {
									createRoundArrowHeadPlus(yPos, height, start, length, orfPolygon);
								}
								// style 1 of polygon ->
								else if (style == 1) {
									createRealArrowHeadPlus(yPos, height, start, length, orfPolygon);
								}
								// style 2 of polygon -- w/o rounded corners
								else if (style == 2) {
									createRectArrowHeadPlus(yPos, height, start, length, orfPolygon);
								}
								// style 3 of polygon -- w/o rounded corners
								else if (style == 3) {
									createRectangle(yPos, height, start, length, orfPolygon);
								}
							}
							// Minus Arrow Head
							else if ((i == 0 || l.getListOfPositions().size() == 1) && l.getStrand().equals("-")) {
								start = (int) ((l.getListOfPositions().get(i).getStart() - 1 - this.viewer.getPositionOfBrowser(trackIndex)) * factor);
								length = (int) ((l.getListOfPositions().get(i).getStop() + 1 - l.getListOfPositions().get(i).getStart()) * factor);

								if (style == 0) {
									createRoundArrowHeadMinus(yPos, height, start, length, orfPolygon);
								} else if (style == 1) {
									createRealArrowHeadMinus(yPos, height, start, length, orfPolygon);
								} else if (style == 2) {
									createRectArrowHeadMinus(yPos, height, start, length, orfPolygon);
								} else if (style == 2) {
									createRectangle(yPos, height, start, length, orfPolygon);
								}
							}
							// No Arrowhead to paint
							else if ((i != l.getListOfPositions().size() - 1 && l.getStrand().equals("+")) || (i != 0 && l.getStrand().equals("-"))) {
								if (style == 0 || style == 2) {
									orfPolygon.addPoint(start, yPos - height / 2);
									orfPolygon.addPoint(start + length, yPos - height / 2);
									orfPolygon.addPoint(start + length, yPos + height / 2);
									orfPolygon.addPoint(start, yPos + height / 2);
								} else if (style == 1) {
									orfPolygon.addPoint(start, yPos - height / 4);
									orfPolygon.addPoint(start + length, yPos - height / 4);
									orfPolygon.addPoint(start + length, yPos + height / 4);
									orfPolygon.addPoint(start, yPos + height / 4);
								} else if (style == 3) {
									createRectangle(yPos, height, start, length, orfPolygon);
								}
							}
							if (rec.contains(orfPolygon.getBounds())) {
								temp.add(l);
								break;
							}
						}
					}
				}
			}
		}
		return temp;
	}

	/**
	 * Paints the track menu
	 * 
	 * @param type
	 *            of visualisation:<br>
	 *            0 = track<br>
	 *            1 = wiggle<br>
	 *            2 = six frame<br>
	 *            3 = dna<br>
	 *            4 = dna -
	 * @param trackIndex
	 *            index of track
	 */
	public void paintSettingsMenu(int type, int trackIndex) {
		Graphics2D g2 = (Graphics2D) this.getGraphics();
		g2.setColor(Color.WHITE);
		g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f));
		g2.fillRect(0, this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y, this.getWidth(), this.getHeight());
		g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
		setInfoWindowVisible(false);
		String menuInfo = "";
		if (type == 0) {
			menuInfo = "Track " + trackIndex;
		} else if (type == 1) {
			menuInfo = "Wiggle-Plot " + trackIndex;
		} else if (type == 2) {
			menuInfo = "Six-Frame-Translation " + trackIndex;
		} else if (type == 3) {
			menuInfo = "DNA-Sequence (+) " + trackIndex;
		} else if (type == -3) {
			menuInfo = "DNA-Sequence (-) " + trackIndex;
		}

		float quarter = (float) this.getWidth() / 4;
		float half = (float) this.getWidth() / 2;
		float threequarter = 3 * ((float) this.getWidth() / 4);
		float height = ((float) viewer.getHeight() / 2) - 64;
		g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
		g2.setFont(new Font("arial", Font.BOLD, 32));
		g2.setColor(Color.DARK_GRAY);
		g2.drawString("SETTINGS", (int) ((float) this.getWidth() * 0.1) + 3, this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y + this.viewer.getHeight() / 2 - 180 + 3);
		g2.setColor(new Color(28, 163, 138));
		g2.drawString("SETTINGS", (int) ((float) this.getWidth() * 0.1), this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y + this.viewer.getHeight() / 2 - 180);

		g2.setFont(new Font("arial", Font.BOLD, 25));
		g2.setColor(this.viewer.getSettings().getLabelingColor());
		g2.drawString(menuInfo, (int) (this.getWidth() * 0.1), this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y + this.viewer.getHeight() / 2 - 150);
		g2.drawString("Size", (int) quarter, this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y + this.viewer.getHeight() / 2 - 90);
		g2.drawString("Look", (int) half, this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y + this.viewer.getHeight() / 2 - 90);
		g2.drawString("Color", (int) threequarter, this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y + this.viewer.getHeight() / 2 - 90);

		ImageIcon size = new ImageIcon(DrawPanel.class.getResource("../resources/size.png"));
		ImageIcon look = new ImageIcon(DrawPanel.class.getResource("../resources/look.png"));
		ImageIcon color = new ImageIcon(DrawPanel.class.getResource("../resources/color.png"));
		g2.drawImage(size.getImage(), Math.round(quarter), Math.round(height) + this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y, this);
		g2.drawImage(look.getImage(), (int) half, (int) height + this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y, this);
		g2.drawImage(color.getImage(), (int) threequarter, (int) height + this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y, this);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
	 */
	public void keyPressed(KeyEvent arg0) {
		// Controlling by keyboard
		// go right
		if (arg0.getKeyCode() == KeyEvent.VK_RIGHT) {
			for (int i = 0; i < this.viewer.getPositionOfTrack().length; i++) {
				this.viewer.setPositionOfBrowser(i, (int) (this.viewer.getPositionOfBrowser(i) + (this.viewer.getRangeOfBrowser() * 0.1)));
			}
		}
		// go left
		else if (arg0.getKeyCode() == KeyEvent.VK_LEFT) {
			for (int i = 0; i < this.viewer.getPositionOfTrack().length; i++) {
				this.viewer.setPositionOfBrowser(i, (int) (this.viewer.getPositionOfBrowser(i) - (this.viewer.getRangeOfBrowser() * 0.1)));
			}
		}
		// zoom in
		else if (arg0.getKeyCode() == KeyEvent.VK_UP) {
			int diff = this.viewer.getRangeOfBrowser();
			this.viewer.setRangeOfBrowser((int) (this.viewer.getRangeOfBrowser() * 0.8));
			diff -= this.viewer.getRangeOfBrowser();
			for (int i = 0; i < this.viewer.getPositionOfTrack().length; i++) {
				this.viewer.setPositionOfBrowser(i, this.viewer.getPositionOfBrowser(i) + diff / 2);
			}
		}
		// zoom out
		else if (arg0.getKeyCode() == KeyEvent.VK_DOWN) {
			int diff = this.viewer.getRangeOfBrowser();
			this.viewer.setRangeOfBrowser((int) (this.viewer.getRangeOfBrowser() * 1.2));
			diff -= this.viewer.getRangeOfBrowser();
			for (int i = 0; i < this.viewer.getPositionOfTrack().length; i++) {
				this.viewer.setPositionOfBrowser(i, this.viewer.getPositionOfBrowser(i) + diff / 2);
			}
		} else if (arg0.getKeyChar() == 'y' && arg0.isControlDown()) {
			this.viewer.createNewBucketWithEmptyFeature();
		} else if (arg0.getKeyChar() == 'x' && arg0.isControlDown()) {
			this.viewer.removeLastBucket();
		} else {

		}
		this.repaint();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
	 */
	public void keyReleased(KeyEvent arg0) {
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
	 */
	public void keyTyped(KeyEvent arg0) {

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent
	 * )
	 */
	public void mouseDragged(MouseEvent e) {
		// mouse dragging
		posMouseDrag = e.getPoint();
		if (e.getModifiersEx() == MouseEvent.BUTTON1_DOWN_MASK) {
			if (dragWiggle != -1 && e.getY() > 2) {
				this.viewer.getSettings().getTracksettings()[dragWiggle].setPositionOfReadWiggle(e.getY());
				setCursor(new Cursor(Cursor.MOVE_CURSOR));

			}
			if (dragTracks != -1 && e.getY() > 2) {
				this.viewer.getSettings().getTracksettings()[dragTracks].setPosition(e.getY());
				setCursor(new Cursor(Cursor.MOVE_CURSOR));

			} else if (dragSixFrameTranslation != -1 && e.getY() > 2 && this.viewer.getRangeOfBrowser() < 100000 && this.viewer.getSettings().getSixFrameSettings()[dragSixFrameTranslation].isSixFrameShown()) {
				this.viewer.getSettings().getSixFrameSettings()[dragSixFrameTranslation].setPosition(e.getY());
				setCursor(new Cursor(Cursor.MOVE_CURSOR));

			} else if (dragDNAMinus != -1 && e.getY() > 2 && this.viewer.getSettings().getSequenceSettings(dragDNAMinus).isShown()) {
				this.viewer.getSettings().getSequenceSettings(dragDNAMinus).setPositionMinusStrand(e.getY());
				setCursor(new Cursor(Cursor.MOVE_CURSOR));

			} else if (dragDNAPlus != -1 && e.getY() > 2 && this.viewer.getSettings().getSequenceSettings(dragDNAPlus).isShown()) {
				this.viewer.getSettings().getSequenceSettings(dragDNAPlus).setPositionPlusStrand(e.getY());
				setCursor(new Cursor(Cursor.MOVE_CURSOR));
			} else if (this.dragWiggle == -1 && e.getY() > 2 && this.dragTracks == -1 && (dragSixFrameTranslation == -1) && !this.showSelectionFrame) {
				setCursor(new Cursor(Cursor.MOVE_CURSOR));
				float x = posMousePress.x - posMouseDrag.x;
				if (x > 400)
					x = 400;
				if (x < -400)
					x = -400;

				float y = posMousePress.y - posMouseDrag.y;

				float zoomfactor = (y) / (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
				float factor = (x) / this.getWidth();

				int diff = this.viewer.getRangeOfBrowser();
				this.viewer.setRangeOfBrowser((int) (this.viewer.getRangeOfBrowser() - (this.viewer.getRangeOfBrowser() * (zoomfactor * 0.6))));

				diff -= this.viewer.getRangeOfBrowser();

				for (int i = 0; i < this.viewer.getPositionOfTrack().length; i++) {
					this.viewer.setPositionOfBrowser(i, this.viewer.getPositionOfBrowser(i) + diff / 2);
					this.viewer.setPositionOfBrowser(i, (int) (this.viewer.getPositionOfBrowser(i) + (this.viewer.getRangeOfBrowser() * (factor * 0.2))));
				}
			}
		}
		this.repaint();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
	 */
	@Override
	public void mouseMoved(MouseEvent e) {
		if (isShowSettingsMenu()) {
			float quarter = (float) this.getWidth() / 4;
			float half = (float) this.getWidth() / 2;
			float threequarter = 3 * ((float) this.getWidth() / 4);
			float height = ((float) viewer.getHeight() / 2) - 64;
			Rectangle size = new Rectangle((int) quarter, (int) height + this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y, 128, 128);
			Rectangle look = new Rectangle((int) half, (int) height + this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y, 128, 128);
			Rectangle color = new Rectangle((int) threequarter, (int) height + this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y, 128, 128);
			if (size.contains(e.getPoint()))
				setCursor(new Cursor(Cursor.HAND_CURSOR));
			else if (look.contains(e.getPoint()))
				setCursor(new Cursor(Cursor.HAND_CURSOR));
			else if (color.contains(e.getPoint()))
				setCursor(new Cursor(Cursor.HAND_CURSOR));
			else {
				setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
			}
			return;
		} else {
			Feature tmp = null;
			if (this.showInformationWindow && !this.showSettingsMenu) {
				tmp = isInTrack(e, e.getPoint());
			}
			if (tmp == null && !this.showSettingsMenu) {
				int isIn = isInWiggle(e, e.getPoint());
				if (isIn != -1) {
					setCursor(new Cursor(Cursor.HAND_CURSOR));
					this.tooltip.setLocation(new Point((int) e.getLocationOnScreen().getX() + 10, (int) (e.getLocationOnScreen().getY() - 10)));
					this.tooltip.setVisible(true);
				} else {
					this.tooltip.setVisible(false);
					setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
				}
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
	 */
	@Override
	public void mouseClicked(MouseEvent arg0) {
		this.requestFocus();
		this.tooltip.setVisible(false);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
	 */
	@Override
	public void mousePressed(MouseEvent arg0) {
		this.posMousePress = arg0.getPoint();
		this.posMouseDrag = arg0.getPoint();
		if (isShowSettingsMenu() && arg0.getButton() == 3) {
			setShowSettingsMenu(false);
			return;
		}
		// MainMenu
		if (isShowSettingsMenu() && arg0.getButton() == 1) {
			float quarter = (float) this.getWidth() / 4;
			float half = (float) this.getWidth() / 2;
			float threequarter = 3 * ((float) this.getWidth() / 4);
			float height = ((float) viewer.getHeight() / 2) - 64;
			Rectangle size = new Rectangle((int) quarter, (int) height + this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y, 128, 128);
			Rectangle look = new Rectangle((int) half, (int) height + this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y, 128, 128);
			Rectangle color = new Rectangle((int) threequarter, (int) height + this.viewer.getDrawPanelScrollPane().getViewport().getViewPosition().y, 128, 128);
			if (size.contains(arg0.getPoint()))
				this.viewer.openSettings(this.selectedMenu, 0);
			else if (look.contains(arg0.getPoint()))
				this.viewer.openSettings(this.selectedMenu, 1);
			else if (color.contains(arg0.getPoint()))
				this.viewer.openSettings(this.selectedMenu, 2);
			setShowSettingsMenu(false);
			return;
		}
		// set position with the aid of wiggle plot
		if (!isShowSettingsMenu() && this.viewer.getNewAnnotationList().size() > 0 && arg0.getClickCount() == 2 && arg0.getButton() == 1) {
			int wigIndex = isInWiggle(arg0, arg0.getPoint());
			if (wigIndex != -1) {
				// and add position tupel
				this.viewer.setPositionToActualCreatedTupel((int) (((float) arg0.getPoint().x / this.getWidth()) * this.viewer.getRangeOfBrowser() + this.viewer.getPositionOfBrowser(wigIndex)));
			}
		}

		// look at tracks
		for (int i = 0; i < this.viewer.getLoadedTracks().length; i++) {
			if (this.viewer.getLoadedTracks()[i] == null)
				continue;

			// show wiggle plot menu
			if (arg0.getY() <= this.viewer.getSettings().getTracksettings()[i].getPositionOfReadWiggle() + 3 && arg0.getY() >= this.viewer.getSettings().getTracksettings()[i].getPositionOfReadWiggle() - 3) {
				this.dragWiggle = i;
				showSelectionFrame = false;

				if (arg0.getButton() == 3) {
					setShowSettingsMenu(true);
					paintSettingsMenu(1, i);
					selectedMenu = new Tupel(1, i);
				}
				break;
			}
			// show track menu
			else if (arg0.getY() <= this.viewer.getSettings().getTracksettings()[i].getPosition() + 3 && arg0.getY() >= this.viewer.getSettings().getTracksettings()[i].getPosition() - 3) {
				this.dragTracks = i;
				showSelectionFrame = false;
				if (arg0.getButton() == 3) {
					setShowSettingsMenu(true);
					paintSettingsMenu(0, i);
					selectedMenu = new Tupel(0, i);
				} else if (arg0.getButton() == 1 && arg0.getClickCount() == 2) {
					this.viewer.getDownPanel().updateSearchBox(i);
					this.viewer.getDownPanel().getFeatureTable().fillTable(i);
					this.viewer.getDownPanel().setFeatureTableName("Track: " + i + " " + this.viewer.getLoadedTracks()[i].getName());
				}
				break;
			}
			// sequence plus menu set up
			else if (i != 0 && arg0.getY() <= (this.viewer.getSettings().getSequenceSettings(i).getPositionPlusStrand() + 3) && arg0.getY() >= (this.viewer.getSettings().getSequenceSettings(i).getPositionPlusStrand() - 3)) {
				this.dragDNAPlus = i;
				showSelectionFrame = false;
				if (arg0.getButton() == 3) {
					setShowSettingsMenu(true);
					paintSettingsMenu(3, i);
					selectedMenu = new Tupel(3, i);
				}
				break;
			}
			// sequence minus menu set up
			else if (i != 0 && arg0.getY() <= (this.viewer.getSettings().getSequenceSettings(i).getPositionMinusStrand() + 3) && arg0.getY() >= this.viewer.getSettings().getSequenceSettings(i).getPositionMinusStrand() - 3) {
				this.dragDNAMinus = i;
				showSelectionFrame = false;
				if (arg0.getButton() == 3) {
					setShowSettingsMenu(true);
					paintSettingsMenu(-3, i);
					selectedMenu = new Tupel(-3, i);
				}
				break;
			}
			// six frame translation menu set up
			else if (arg0.getY() <= this.viewer.getSettings().getSixFrameSettings()[i].getPosition() + 3 && arg0.getY() >= this.viewer.getSettings().getSixFrameSettings()[i].getPosition() - 3) {
				this.dragSixFrameTranslation = i;
				showSelectionFrame = false;
				if (arg0.getButton() == 3) {
					setShowSettingsMenu(true);
					paintSettingsMenu(2, i);
					selectedMenu = new Tupel(2, i);
				}
				break;
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
	 */
	@Override
	public void mouseReleased(MouseEvent arg0) {
		if (this.isShowSettingsMenu())
			return;
		setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
		this.dragWiggle = -1;
		this.dragTracks = -1;
		this.dragSixFrameTranslation = -1;
		this.dragDNAMinus = -1;
		this.dragDNAPlus = -1;
		this.viewer.getPopUpMenu().setVisible(false);

		if (posMousePress.distance(posMouseDrag) > 5 && this.showSelectionFrame && this.isSelectSequences) {
			int minX = Math.min(posMouseDrag.x, posMousePress.x);
			int maxX = Math.max(posMouseDrag.x, posMousePress.x);

			int minY = Math.min(posMouseDrag.y, posMousePress.y);
			int maxY = Math.max(posMouseDrag.y, posMousePress.y);

			setPositionOfFeaturesByFrame(new Rectangle(minX, minY, maxX - minX, maxY - minY));
		}
		// normal selection frame to select features if selectionFrameMode is
		// enabled and Ctrl is NOT pressed
		else if (posMousePress.distance(posMouseDrag) > 5 && this.showSelectionFrame && !this.isSelectSequences) {
			int minX = Math.min(posMouseDrag.x, posMousePress.x);
			int maxX = Math.max(posMouseDrag.x, posMousePress.x);

			int minY = Math.min(posMouseDrag.y, posMousePress.y);
			int maxY = Math.max(posMouseDrag.y, posMousePress.y);

			FeatureHolder temp = new FeatureHolder();
			temp.setTypeOfFile("gff");
			temp.addAll(isInSelectionFrame(new Rectangle(minX, minY, maxX - minX, maxY - minY)));

			if (arg0.isControlDown()) {
				for (int i = 0; i < temp.size(); i++) {
					if (!this.viewer.getSelectedFeatureList().contains(temp.get(i))) {
						this.viewer.getSelectedFeatureList().add(temp.get(i));
					} else if (this.viewer.getSelectedFeatureList().contains(temp.get(i))) {
						this.viewer.getSelectedFeatureList().remove(temp.get(i));
					}
				}
			}
			if (!arg0.isControlDown()) {
				this.viewer.getSelectedFeatureList().clear();
				this.viewer.setSelectedFeatureList(temp);
			}
			this.repaint();

		} else {
			Feature feature = isInTrack(arg0, arg0.getPoint());

			if (feature == null && arg0.getButton() == 3) {
				this.viewer.getPopUpMenu().setVisible(true);
				this.viewer.getPopUpMenu().setLocation(arg0.getXOnScreen(), arg0.getYOnScreen());
			} 
			
			else if (feature != null && arg0.getButton() == 3 && !this.showInformationWindow) {
				
			} else if (feature == null && arg0.getButton() == 1) {
				this.viewer.getSelectedFeatureList().removeAll(this.viewer.getSelectedFeatureList());
			} else if (arg0.isControlDown() && feature != null && arg0.getButton() == 1) {

				if (!this.viewer.getSelectedFeatureList().contains(feature)) {
					this.viewer.getSelectedFeatureList().add(feature);
				} else if (this.viewer.getSelectedFeatureList().contains(feature)) {
					this.viewer.getSelectedFeatureList().remove(feature);
				}
			} else if (feature != null && arg0.getButton() == 1) {
				this.viewer.getSelectedFeatureList().removeAll(this.viewer.getSelectedFeatureList());
				this.viewer.getSelectedFeatureList().add(feature);
			}
			this.repaint();
		}
		this.posMousePress = arg0.getPoint();
		this.posMouseDrag = arg0.getPoint();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
	 */
	@Override
	public void mouseEntered(MouseEvent arg0) {
	}

	@Override
	public void mouseWheelMoved(MouseWheelEvent e) {
		int diff = this.viewer.getRangeOfBrowser();
		switch (e.getWheelRotation()) {
		case 1:
			this.viewer.setRangeOfBrowser((int) (this.viewer.getRangeOfBrowser() * 1.2));
			diff -= this.viewer.getRangeOfBrowser();
			for (int i = 0; i < this.viewer.getPositionOfTrack().length; i++) {
				this.viewer.setPositionOfBrowser(i, this.viewer.getPositionOfBrowser(i) + diff / 2);
			}
			break;
		case -1:
			this.viewer.setRangeOfBrowser((int) (this.viewer.getRangeOfBrowser() * 0.8));
			diff -= this.viewer.getRangeOfBrowser();
			for (int i = 0; i < this.viewer.getPositionOfTrack().length; i++) {
				this.viewer.setPositionOfBrowser(i, this.viewer.getPositionOfBrowser(i) + diff / 2);
			}
			break;
		}
		this.repaint();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
	 */
	@Override
	public void mouseExited(MouseEvent arg0) {
	}

	/**
	 * Sets the wiggle plot tool tip invisile or not
	 * 
	 * @param showToolTips
	 */
	public void setShowToolTips(boolean showToolTips) {
		this.showInformationWindow = showToolTips;
		if (!showToolTips) {
			this.informationWindow.setVisible(false);
		}
	}

	/**
	 * Sets the information window invisible or not
	 * 
	 * @param bool
	 */
	public void setInfoWindowVisible(boolean bool) {
		this.informationWindow.setVisible(bool);
	}

	/**
	 * Returns if the wiggle plot is visisble
	 * 
	 * @return is the wiggle plot info shown?
	 */
	public boolean isShowToolTips() {
		return showInformationWindow;
	}

	/**
	 * Returns if the wiggle plot tool tip is visible
	 * 
	 * @return is the wiggle plot info shown
	 */
	public WiggleInfoWindow getTooltip() {
		return tooltip;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.event.FocusListener#focusGained(java.awt.event.FocusEvent)
	 */
	public void focusGained(FocusEvent arg0) {
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent)
	 */
	public void focusLost(FocusEvent arg0) {
		this.tooltip.setVisible(false);
		this.informationWindow.setVisible(false);
	}

	/**
	 * Sets the menu visible or not
	 * 
	 * @param showSettingsMenu
	 *            the showSettingsMenu to set
	 */
	public void setShowSettingsMenu(boolean showSettingsMenu) {
		this.dragDNAMinus = -1;
		this.dragDNAPlus = -1;
		this.dragSixFrameTranslation = -1;
		this.dragTracks = -1;
		this.dragWiggle = -1;
		this.showSettingsMenu = showSettingsMenu;
	}

	/**
	 * Returns the visibility of the menu
	 * 
	 * @return is the menu shown
	 */
	public boolean isShowSettingsMenu() {
		return showSettingsMenu;
	}

	/**
	 * Sets the information visible or not
	 * 
	 * @param showInformationWindow
	 */
	public void setShowInformationWindow(boolean showInformationWindow) {
		this.showInformationWindow = showInformationWindow;
		this.informationWindow.setVisible(showInformationWindow);
	}

	/**
	 * Returns the visibility of the information window
	 * 
	 * @return is the information window shown
	 */
	public boolean isShowInformationWindow() {
		return showInformationWindow;
	}

	/**
	 * Enables/Disables the selection Frame
	 * 
	 * @param showSelectionFrame
	 */
	public void setShowSelectionFrame(boolean showSelectionFrame) {
		this.showSelectionFrame = showSelectionFrame;
	}

	/**
	 * Is the selection fame enabled or not
	 * 
	 * @return is the selection frame shown
	 */
	public boolean isShowSelectionFrame() {
		return showSelectionFrame;
	}

	/**
	 * Is the selection fame enabled or not
	 * 
	 * @return is selectect sequences mode enabled
	 */
	public boolean isSelectionSequences() {
		return this.isSelectSequences;
	}

	/**
	 * Sets if the selection mode is enabled or not
	 * 
	 * @param isSelectSequences
	 */
	public void setSelectSequences(boolean isSelectSequences) {
		this.isSelectSequences = isSelectSequences;
	}
}